Я хотел бы иметь новый экземпляр IJob для каждого выполнения. Вот как у меня настроена работа:
[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);
}
}
Вот как я планирую это задание для выполнения. Идея заключается в том, чтобы запускать одновременные выполнения для разных «групп», чтобы эти экземпляры запускались по одному и тому же расписанию. Но я вижу один и тот же идентификатор экземпляра во всех журналах для всех групп.
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());
}
Я не знаю как
JobBuilder.Создать<>()
Работает. Кажется, он игнорирует атрибут MEF и использует свой собственный контейнер? Я ожидаю, что у меня будет новый экземпляр каждый раз, когда я запускаю JobBuilder.Create<>, но не вижу его.
Обновлено: Подробнее
Код запускается внутри проекта службы Windows. Внутри конструктора ServiceBase выполняется следующий код. После создания этих объектов я планирую задания, как показано выше. Для их создания использовался Qauartz.JobBuilder (не пользовательский). Другого кода нет, особенно ничего о настройке MEF для 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: Детали фабрики заданий, это единственное место, созданное вручную. Похоже, здесь мне нужно предоставить исправление, создав экземпляр вручную вместо использования предварительно импортированного списка? Вроде отвечаю на свой вопрос..
[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)
{
}
}
Вам необходимо предоставить более подробную информацию. По умолчанию JobFactory должен каждый раз создавать новый экземпляр. Вы сказали, что, возможно, он игнорирует MEF, но каким-то образом устанавливает ваш LoggerService?
@Evk да, вы правы, он использует MEF, потому что внедряет службу Logger. Но экземпляр TestProcessor всего один, это моя проблема.
Как я уже упоминал, я считаю, что стоит добавить больше кода, например, как вы настраиваете кварц (в частности, как вы настраиваете его для работы с MEF). Может быть, у вас есть пользовательский конструктор заданий?
@Evk - отредактировал сообщение, добавил больше деталей. Похоже, я получил свой ответ, пожалуйста, опубликуйте фактический ответ, чтобы получить награду
Как вы уже поняли, у вас есть кастомный JobBuilder, который отвечает за создание новых экземпляров заданий. В этом компоновщике у вас есть статический список экземпляров заданий (List<IJob> Jobs), импортированных из MEF, а затем вы получаете экземпляр из этого списка на основе запрошенного JobType. Итак, в результате вы действительно явно сделали так, чтобы каждый раз возвращался один экземпляр TestProcessor.
Спасибо! Иногда просто нужен другой набор глаз.
Можете ли вы проверить это, как создать экземпляр - github.com/quartznet/quartznet/blob/…