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.