.NET Quartz定时作业执行异常后如何配置立即重新触发?
问题解答
核心结论
抛出配置了refireImmediately = true的JobExecutionException确实可以实现作业异常后立即重新触发,完全符合你的预期。
这是Quartz框架专门设计的异常调度控制机制,和普通异常的处理逻辑完全不同:
- 你之前直接
throw;抛出普通异常时,Quartz调度器会默认将本次作业标记为执行失败,不会触发重试,只会等待触发器的下一个预设触发时间(也就是次日的固定执行时间)。 JobExecutionException属于Quartz专门定义的调度控制异常,即使从Execute方法向外抛出,调度器也会专门识别处理,既不会影响服务整体运行,还会按照你配置的参数执行重跑逻辑。
代码修改示例
基础立即重试版本
直接修改catch块的抛出逻辑即可:
public Task Execute(IJobExecutionContext context) { try { // DoStuff } catch (Exception ex) { _logger.LogError(ex, "DailyJob执行失败,即将立即重试"); // 第二个参数即refireImmediately,设为true即可触发立即重试 throw new JobExecutionException(ex, refireImmediately: true); } return Task.CompletedTask; }
带重试次数限制的优化版本
上述基础版本会在故障持续存在时触发无限重试,占用系统资源,建议添加上限控制:
public Task Execute(IJobExecutionContext context) { // 从JobDataMap获取当前重试次数,默认0 var retryCount = context.JobDetail.JobDataMap.GetInt("RetryCount", 0); const int maxRetryCount = 3; try { // DoStuff // 执行成功后重置重试次数 context.JobDetail.JobDataMap.Put("RetryCount", 0); } catch (Exception ex) { retryCount++; _logger.LogError(ex, "DailyJob执行失败,当前重试次数:{RetryCount}/最大重试次数:{MaxRetryCount}", retryCount, maxRetryCount); if (retryCount <= maxRetryCount) { // 更新重试次数到JobDataMap context.JobDetail.JobDataMap.Put("RetryCount", retryCount); // 未达最大重试次数则立即重试 throw new JobExecutionException(ex, refireImmediately: true); } // 超过最大重试次数,重置重试次数,等待下一次调度 context.JobDetail.JobDataMap.Put("RetryCount", 0); _logger.LogError("DailyJob超过最大重试次数,放弃本次执行,等待下一次调度"); } return Task.CompletedTask; }
注意事项
- 你已添加
[DisallowConcurrentExecution]特性,重跑过程中不会出现多个作业实例并行执行的问题,不会产生数据冲突。 - JobDataMap默认是持久化的,如果你使用了持久化调度器,重试次数会在服务重启后依然保留;如果不需要持久化重试次数,可以使用
context.Put将次数存在本次执行的上下文里。
内容的提问来源于stack exchange,提问作者TheDoomDestroyer
相关产品推荐
相关产品推荐

