如何让JobDataMap的修改在Quartz.NET的其他作业上下文可见?
问题:修改Quartz.NET作业JobDataMap后无法在其他作业中生效
我有一个ReloadJob,用于修改调度器中所有其他作业的JobDataMap,但在另一个作业的上下文里获取JobDetail时,得到的是空的JobDataMap。我知道修改仅在当前上下文可见,请问是否有办法让所有调度器作业都能看到这些修改?
ReloadJob代码:
[PersistJobDataAfterExecution] [DisallowConcurrentExecution] public class ReloadJob : IJob { public async Task Execute(IJobExecutionContext context) { try { GetJobs(); } catch(Exception ex) { JobExecutionException jex = new JobExecutionException(ex, false); throw jex; } } private async void GetJobs() { IScheduler scheduler = await SchedulerRepository.Instance.Lookup("ConsoleScheduler"); var jobGroups = scheduler.GetJobGroupNames().Result; foreach (string group in jobGroups) { var groupMatcher = GroupMatcher<JobKey>.GroupContains(group); var jobKeys = scheduler.GetJobKeys(groupMatcher).Result; foreach (var jobKey in jobKeys) { var detail = scheduler.GetJobDetail(jobKey).Result; var triggers = scheduler.GetTriggersOfJob(jobKey).Result; detail.JobDataMap.Put("Reload", "yes"); foreach (ITrigger trigger in triggers) { Console.WriteLine(detail.JobType.Name); Console.WriteLine(detail.JobDataMap.Get("Reload")); } } } } }
另一个作业获取JobDataMap的代码:
public async Task Execute(IJobExecutionContext context) { var temp = context.JobDetail.JobDataMap; }
注:[PersistJobDataAfterExecution]和[DisallowConcurrentExecution]仅在修改所在的上下文生效。
解决方案
要让修改的JobDataMap持久化到Quartz存储中,让所有作业都能读取到,你需要调用scheduler.AddJob()方法并传入true参数覆盖已存在的作业详情——直接修改从调度器获取的JobDetail只是内存副本,不会自动同步到Quartz的持久化存储。
修改后的GetJobs()方法:
private async Task GetJobs() // 替换async void为async Task,避免异步异常无法捕获 { IScheduler scheduler = await SchedulerRepository.Instance.Lookup("ConsoleScheduler"); var jobGroups = await scheduler.GetJobGroupNames(); // 用await替代.Result,避免阻塞死锁 foreach (string group in jobGroups) { var groupMatcher = GroupMatcher<JobKey>.GroupContains(group); var jobKeys = await scheduler.GetJobKeys(groupMatcher); foreach (var jobKey in jobKeys) { var detail = await scheduler.GetJobDetail(jobKey); // 修改JobDataMap detail.JobDataMap.Put("Reload", "yes"); // 覆盖原作业,第二个参数true表示允许替换已存在的作业 await scheduler.AddJob(detail, true); var triggers = await scheduler.GetTriggersOfJob(jobKey); foreach (ITrigger trigger in triggers) { Console.WriteLine(detail.JobType.Name); Console.WriteLine(detail.JobDataMap.Get("Reload")); } } } }
额外注意事项:
- 避免使用
async void,改用async Task保证异步异常能被捕获处理 - 用
await替代.Result,防止异步操作中的阻塞和死锁问题 - 其他作业获取最新JobDataMap时,可以选择两种方式:
- 从上下文的
MergedJobDataMap获取(合并了作业和触发器的DataMap) - 从调度器重新拉取最新的JobDetail
- 从上下文的
示例:
public async Task Execute(IJobExecutionContext context) { // 方式1:获取合并后的JobDataMap var mergedData = context.MergedJobDataMap; string reloadFlag = mergedData.GetString("Reload"); // 方式2:从调度器获取最新的JobDetail var latestDetail = await context.Scheduler.GetJobDetail(context.JobDetail.Key); string latestReloadFlag = latestDetail.JobDataMap.GetString("Reload"); }
内容的提问来源于stack exchange,提问作者Lozko Danila
相关产品推荐
相关产品推荐

