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
JobBuilderwhich 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 requestedJobType. So in result you indeed explicitly made it so that single instance ofTestProcessoris being returned every time.