嗨,我正在使用Simple Injector,我正在尝试实现一个调度程序服务,该服务以可编程的常规频率调用命令。我的设计决策如下:
1)我有一个运行后台线程并从容器解析ICommandHandler<SyncExternalDataCommand>.Handle(someParameter)
并调用命令句柄方法的服务。
RegisterCommandAsBusinessUnitCronJob
将为每个 BusinessUnit 调用,并在每次调用时将 ID 作为参数传递。我们还可以实现RegistercommandAsCustomerContactCronJob
遍历客户记录。
用后台线程这样设计调度器可以吗?
2)我试图将组合根容器和调度程序之间的耦合保持在最低限度。
使用 Action 助手委托的方法有助于将代码保留在组合根部分中,而不是在服务中。通过使用不同的设计,这种耦合是否可以进一步减少,或者这种耦合是否可以接受?
代码如下(它尚未成为线程安全的),非常欢迎对上面的设计决策和改进/重新设计发表评论。
谢谢,克里斯
容器的引导
void Register(Container container)
{
container.RegisterSingle<IUnitOfWorkFactory>(
new UnitOfWorkFactory(container));
container.RegisterLifetimeScope<IUnitOfWork, UnitOfWork>();
container.RegisterSingle<ILogger, Logger>();
container.RegisterSingle<ICronJobService, CronJobService>();
container.Register<ICommandHandler<SyncExternalDataCommand>,
SyncExternalDataCommandHandler>();
var cronJobService = container.GetInstance<ICronJobService>();
cronJobService.RegisterCommandAsBusinessUnitCronJob("* 1 * * *",
(Int32 id) =>
{
var command = new SyncExternalDataCommand()
{
businessUnitId = id
};
using (container.BeginLifetimeScope())
{
// handler must be resolved INSIDE the scope.
var handler =
container.GetInstance<ICommandHandler<SyncExternalDataCommand>>();
handler.Handle(command);
}
}
);
}
调度服务
// to be instantiated as a singleton by IoC container
public class CronJobService : ICronJobService
{
// this dictionary is for tasks that will be called with
// the business unit primary key (Int32).
private cronJobs = new Dictionary<Action<Int32>, string>();
public void RegisterCommandAsBusinessUnitCronJob(
string cronString, Action<Int32> commandFactory)
{
cronJobs.Add(commandFactory, cronString);
}
// this below is called when we are running a task
protected static bool RunCreateAndHandleThread(
object parameter)
{
var jobParameters = (ThreadJobParameters)parameter;
if (!cancellationTokenSource.IsCancellationRequested)
{
// we will need to construct new graph with a
// proxy command
jobParameters.helper(jobParameters.businessUnitId);
}
return true;
}
protected static void SomeBackgroundLoop(
RunHandlePollingLoopParameters parameters)
{
IUnitOfWork unitOfWork =
parameters.unitOfWorkFactory.CreateUnitOfWork();
using (unitOfWork)
{
var businessUnits =
unitOfWork.BusinessUnitRepository.Get();
// loop through cron jobs and business units
foreach (var helperFactory in parameters.cronJobs.Keys)
{
// its time to run this job...
if (isTimeToRunCronjob)
{
var jobParameters = new ThreadJobParameters
{
helper = helperFactory,
businessUnitId = businessUnit.Id
};
Task.Factory.StartNew<bool>(
RunCreateAndHandleThread,
jobParameters,
CronJobService.cancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
}
}
}
}
}