简体   繁体   中英

Quartz.NET JobBuilder.Create<> reuses same instance of IJob

I would like to have new instance of IJob for every execution. Here is how I have job setup:

[Export(typeof(IJob))]
[PartCreationPolicy(CreationPolicy.NonShared)]
[DisallowConcurrentExecution]
public class TestProcessor : IJob
{
    [Import]
    public ILoggerService LoggerService { get; set; }
    
    private string InstanceId { get; }

    public TestProcessor()
    {
        this.InstanceId = Guid.NewGuid().ToString().Substring(0, 4);
    }

    public void Execute(IJobExecutionContext context)
    {        
        // TODO: Here I expect to see log entry with different InstanceId every time
        string processGroupId = null;
        if (context != null && context.MergedJobDataMap.ContainsKey(JobListener.ProcessGroupId))
            processGroupId = context.MergedJobDataMap[JobListener.ProcessGroupId].ToString();

        this.LoggerService.Log(null, $"TEST: Group: {processGroupId}, JobInstance: {this.InstanceId}, ServiceInstance: {this.FuelPriceService.InstanceId}", Category.Debug, Priority.Low);
                
    }
}

Here is how I schedule this job for execution. Idea here, to run concurrent executions for different "groups" so those instances run on same schedule. But I see same instance Id in all Logs for all groups

foreach (var pgId in processGroups)
{    
    // Test Processor
    var testJobDetail = JobBuilder.Create<TestProcessor>().Build();
    testJobDetail.JobDataMap.Add(JobListener.ProcessGroupId, pgId);
    testJobDetail.JobDataMap.Add(JobListener.TimeLimitSeconds, "300");
    
    this.scheduler.ScheduleJob(testJobDetail, TriggerBuilder.Create().WithCronSchedule("0 0/5 * * * ?").Build());
}

I am not sure how

JobBuilder.Create<>()

works. It seems to ignore MEF attribute and uses its own container? I expect to have new instance every time I run JobBuilder.Create<> but not seeing it.

EDIT : More details

Code runs inside windows service project. Inside ServiceBase constructor following code executed. After those objects created I schedule jobs like shown above. Qauartz.JobBuilder used to create them (not custom one). There is no other code, specifically nothing about configuring MEF for Quartz.

// Import job factory 
var jobFactoryInstance = Bootstrapper.CompositionContainer.GetExports<IJobFactory>().FirstOrDefault();
if (jobFactoryInstance == null) throw new InvalidOperationException("Job Factory instance wasn't created!");
var jobFactory = jobFactoryInstance.Value;

// construct a scheduler factory
ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
this.scheduler = schedulerFactory.GetScheduler();
this.scheduler.JobFactory = jobFactory;

// Import job listener
var jobListenerInstance = Bootstrapper.CompositionContainer.GetExports<IJobListener>().FirstOrDefault();
if (jobListenerInstance == null) throw new InvalidOperationException();
var jobListener = jobListenerInstance.Value;
this.scheduler.ListenerManager.AddJobListener(jobListener, EverythingMatcher<JobKey>.AllJobs());

EDIT2 : Job factory details, this is only place that manually instantiated. Looks like this is where I need to provide fix by manually creating instance instead of using pre-imported list? Sounds like I am answering my q..

[Export(typeof(IJobFactory))]
public class JobFactory : IJobFactory
{
    [ImportMany(typeof(IJob))]
    public List<IJob> Jobs { get; private set; }

    public virtual IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        try
        {
            Debug.WriteLine("IDATT.WindowsService.JobFactory - getting job from a list");
            return this.Jobs.First(j => j.GetType() == bundle.JobDetail.JobType);
        }
        catch (Exception e)
        {
            var se = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "Problem instantiating class '{0}'", bundle.JobDetail.JobType.FullName), e);
            throw se;
        }
    }

    public virtual void ReturnJob(IJob job)
    {
    }
}

As you already found - you have custom JobBuilder which is responsible for creating new job instances. In that builder you have static list of job instances ( List<IJob> Jobs ) imported from MEF, and then you getting an instance from that list based on requested JobType . So in result you indeed explicitly made it so that single instance of TestProcessor is being returned every time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM