Quartz, Unity & .NET

Is it possible to register a quartz job to always use the same IJob instance introduced by the Unity DI container? I have one instance of the “monitor” class Monitor , coming from Unity DI, which I registered as:

 container.RegisterType<IMonitor, Monitor>(new ContainerControlledLifetimeManager()) 

and my IJob implementation assumes an instance of this monitor is injected into it:

 class MyJob : IJob { ... [Dependency] IMonitor monitor {get; set;} ... void Execute() ... } 

but when an event of quartz events occurs, the implementation of IJob.Execute() is called before the dependency is introduced. How do I make this work? Should I consider other DI containers or schedulers instead?

thanks

+6
source share
4 answers

Quartz will restore the implementation of the operation interface for every fire event. It is recommended that you use IStatefulJob if you want to maintain state between jobs:

IStatefulJob identifiers follow slightly different rules from regular IJob Instances. The main difference is that their associated JobDataMap is re-saved after each job execution , thereby saving for the next run. Another difference is that the state of tasks is not allowed to be executed simultaneously, which means new triggers that occur before the completion of the IJob.Execute method will be delayed.

From quartz tutorial :

StatefulJob

Now, some additional notes about job status data (aka JobDataMap): A job instance can be defined as "stateful" or "non-stateful". Non-stationary jobs only have JobDataMap stored at the time they are added to the scheduler. This means that any changes made to the contents of the task data card during the task will be lost and will not see this task the next time. You probably guessed that working with a state is just the opposite - its JobDataMap is re-saved after each job execution. One side effect of doing work with a state is that it cannot be executed at the same time. Or in other words: if the task is well-founded, and the trigger tries to “burn”, the task, while it is already running, the trigger will block (wait) until the previous execution is completed.

You mark “Work as a state when it implements the StatefulJob interface, not the Job interface.

Another option for you is to implement your own JobFactory:

Instances Task

A final question on this topic, which may or may not be obvious at this time: You can create one job class and save multiple instances of defining it in the scheduler by creating several instances of JobDetails - each with its own set of properties and JobDataMap - and adding them to the scheduler .

When a trigger fires, the task associated with it is created through the JobFactory configured in the Scheduler. By default, JobFactory simply calls newInstance () on the job class. You might want to create your own JobFactory implementation to achieve goals such as producing / initializing a job with your IoC program or DI container .

+5
source

Take a look at Quartz.Unity.

https://www.nuget.org/packages/Quartz.Unity/1.0.1

The Doc is very sparse, but it seems that all you need to do is add the nuget package and the following line to your container configuration.

 var container = new UnityContainer().AddNewExtension<Quartz.Unity.QuartzUnityExtension>(); 
+5
source

You can do this by implementing your own JobFactory. You need to implement the IJobFactory interface:

 public interface IJobFactory { /// <summary> /// Called by the scheduler at the time of the trigger firing, in order to /// produce a <see cref="IJob" /> instance on which to call Execute. /// </summary> /// <remarks> /// <p> /// It should be extremely rare for this method to throw an exception - /// basically only the the case where there is no way at all to instantiate /// and prepare the Job for execution. When the exception is thrown, the /// Scheduler will move all triggers associated with the Job into the /// <see cref="TriggerState.Error" /> state, which will require human /// intervention (eg an application restart after fixing whatever /// configuration problem led to the issue wih instantiating the Job. /// </p> /// /// </remarks> /// <param name="bundle"> /// The TriggerFiredBundle from which the <see cref="JobDetail" /> /// and other info relating to the trigger firing can be obtained. /// </param> /// <throws> SchedulerException if there is a problem instantiating the Job. </throws> /// <returns> the newly instantiated Job /// </returns> IJob NewJob(TriggerFiredBundle bundle); } 

Then set the scheduler property quartz.scheduler.jobFactory.type to your factory job.

For reference, here is the factory default job that quartz.net uses:

 public class SimpleJobFactory : IJobFactory { private static readonly ILog Log = LogManager.GetLogger(typeof (SimpleJobFactory)); /// <summary> /// Called by the scheduler at the time of the trigger firing, in order to /// produce a <see cref="IJob" /> instance on which to call Execute. /// </summary> /// <remarks> /// It should be extremely rare for this method to throw an exception - /// basically only the the case where there is no way at all to instantiate /// and prepare the Job for execution. When the exception is thrown, the /// Scheduler will move all triggers associated with the Job into the /// <see cref="TriggerState.Error" /> state, which will require human /// intervention (eg an application restart after fixing whatever /// configuration problem led to the issue wih instantiating the Job. /// </remarks> /// <param name="bundle">The TriggerFiredBundle from which the <see cref="JobDetail" /> /// and other info relating to the trigger firing can be obtained.</param> /// <returns>the newly instantiated Job</returns> /// <throws> SchedulerException if there is a problem instantiating the Job. </throws> public virtual IJob NewJob(TriggerFiredBundle bundle) { JobDetail jobDetail = bundle.JobDetail; Type jobType = jobDetail.JobType; try { if (Log.IsDebugEnabled) { Log.Debug(string.Format(CultureInfo.InvariantCulture, "Producing instance of Job '{0}', class={1}", jobDetail.FullName, jobType.FullName)); } return (IJob) ObjectUtils.InstantiateType(jobType); } catch (Exception e) { SchedulerException se = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "Problem instantiating class '{0}'", jobDetail.JobType.FullName), e); throw se; } } } 

Interesting line:

  return (IJob) ObjectUtils.InstantiateType(jobType); 
+2
source

Create a CustomJobfactory that overrides SimpleJobFactory and uses spring to instantiate job classes.

 /// <summary> /// Custom Job Factory /// </summary> public class CustomJobFactory : SimpleJobFactory { /// <summary> /// Application context /// </summary> private IApplicationContext context; /// <summary> /// Initializes a new instance of the <see cref="CustomJobFactory" /> class. /// </summary> public CustomJobFactory() { this.context = ContextRegistry.GetContext(); } /// <summary> /// Creates a new job instance /// </summary> /// <param name="bundle">Trigger bundle</param> /// <param name="scheduler">Job scheduler</param> /// <returns></returns> public override IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) { IJobDetail jobDetail = bundle.JobDetail; Type jobType = jobDetail.JobType; return this.context.GetObject(jobType.Name) as IJob; } /// <summary> /// Return job /// </summary> /// <param name="job">Job instance</param> public override void ReturnJob(IJob job) { } } 
0
source

Source: https://habr.com/ru/post/897169/


All Articles