Note that there are some explanatory texts on larger screens.

plurals
  1. POIoC Task Scheduler Design with Simple Injector with code example recommendations
    text
    copied!<p>Hi I am using <a href="http://simpleinjector.codeplex.com/" rel="nofollow">Simple Injector</a> and I am trying to implement a scheduler service which calls command(s) at a programmable regular frequency. My design decisions are below:</p> <p>1) I have a service that runs a background thread and resolves from the container <code>ICommandHandler&lt;SyncExternalDataCommand&gt;.Handle(someParameter)</code> and calls the command handle method.</p> <p><code>RegisterCommandAsBusinessUnitCronJob</code> will be called for each BusinessUnit with the ID passed as a parameter on each call. We could also implement <code>RegistercommandAsCustomerContactCronJob</code> to loop through customer records. </p> <p><strong>Is it ok to design the scheduler in this way with a background thread?</strong></p> <p>2) I have tried to keep the coupling between the composition root container and the scheduler to a minimum.</p> <p>An approach with Action helper delegates helps to keep the code in the composition root section as opposed to within the service. <strong>By using a different design, could this coupling be reduced further or is this coupling acceptable?</strong></p> <p>Code is below (it is yet to be made thread-safe), comments on the design decisions above and improvements/redesign are very welcome.</p> <p>Thanks, Chris</p> <p><strong>Bootstrap of the container</strong></p> <pre class="lang-cs prettyprint-override"><code>void Register(Container container) { container.RegisterSingle&lt;IUnitOfWorkFactory&gt;( new UnitOfWorkFactory(container)); container.RegisterLifetimeScope&lt;IUnitOfWork, UnitOfWork&gt;(); container.RegisterSingle&lt;ILogger, Logger&gt;(); container.RegisterSingle&lt;ICronJobService, CronJobService&gt;(); container.Register&lt;ICommandHandler&lt;SyncExternalDataCommand&gt;, SyncExternalDataCommandHandler&gt;(); var cronJobService = container.GetInstance&lt;ICronJobService&gt;(); cronJobService.RegisterCommandAsBusinessUnitCronJob("* 1 * * *", (Int32 id) =&gt; { var command = new SyncExternalDataCommand() { businessUnitId = id }; using (container.BeginLifetimeScope()) { // handler must be resolved INSIDE the scope. var handler = container.GetInstance&lt;ICommandHandler&lt;SyncExternalDataCommand&gt;&gt;(); handler.Handle(command); } } ); } </code></pre> <p><strong>Scheduler service</strong></p> <pre class="lang-cs prettyprint-override"><code>// 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&lt;Action&lt;Int32&gt;, string&gt;(); public void RegisterCommandAsBusinessUnitCronJob( string cronString, Action&lt;Int32&gt; 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&lt;bool&gt;( RunCreateAndHandleThread, jobParameters, CronJobService.cancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); } } } } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload