レガシー アプリケーションのリファクタリングを行っています。問題のアプリケーションは、SQL Server データベース テーブルを使用して、1 つ以上の Windows サービスによって取得および処理されるジョブをキューに入れます。適切なロックを維持しながら、処理のために「待機中」ステータスでキューに入れられた次のジョブをプルするイテレータを作成したいと考えています。サンプル単体テストが以下に含まれています。私の質問は、私のアプローチに潜在的なショーストッパーがあるかどうかです。
// Database DDL
if object_id('Jobs') is not null begin
drop table Jobs;
end
go
create table Jobs
(
Id int identity(1,1) not null primary key clustered
, JobStatus varchar(50) not null
);
insert Jobs
select 'Waiting'
union all
select 'Waiting'
union all
select 'Processing'
union all
select 'Completed'
union all
select 'Failed';
// Unit Test
// Data Model
public sealed class Job
{
public readonly int JobId;
public Job(int jobId)
{
JobId = jobId;
}
}
[TestFixture]
public class JobsTest
{
private const string connectionString =
"Data Source=.;Initial Catalog=<databasename>;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False";
const string SQL =
@"declare @jobId table(JobId int)
update top(1) Jobs
set JobStatus = 'Processing'
output Inserted.Id into @jobId
where JobStatus = 'Waiting'
select JobId from @jobId;";
[Test]
public void CanIterateJobs()
{
foreach (var job in Jobs)
{
Assert.NotNull(job, "job was null.");
Console.WriteLine(job.JobId);
}
}
public static IEnumerable<Job> Jobs
{
get
{
while (true)
{
Job job = null;
do
{
using (var connection = new SqlConnection(connectionString))
{
using (var command = new SqlCommand(SQL, connection))
{
connection.Open();
var reader = command.ExecuteReader();
if (reader.Read())
{
job = new Job(Convert.ToInt32(reader["JobId"]));
yield return job;
}
}
}
} while (job == null);
Task.Delay(1000);
}
}
}
}