Jobrunr重试任务时调度与入队状态间延迟过高问题排查
环境与问题现象
使用Jobrunr 6.1.0,以Redis作为存储Provider,整体运行正常,但重试任务时调度时间与入队时间存在数小时延迟。仪表盘时间线示例:
Job scheduled - Retry 1 of 5 - Wed Jun 14 2023 22:55:12 GMT+0200 Job enqueued - Thu Jun 15 2023 00:03:15 GMT+0200 Processing Job - Thu Jun 15 2023 00:03:25 GMT+0200 Job processing failed - Thu Jun 15 2023 00:00:25 GMT+0200 Job scheduled - Retry 2 of 5 - Wed Jun 14 2023 00:04:01 GMT+0200 Job enqueued - Thu Jun 15 2023 00:45:08 GMT+0200 Processing Job - Thu Jun 15 2023 00:45:11 GMT+0200 Job processing failed - Thu Jun 15 2023 00:45:12 GMT+0200
每日任务量约1000个,自定义配置如下:
numberOfRetries = 5 backOffPolicyTimeSeed = 6 dashboardEnabled = true dashboardPort = 8000 backgroundJobServerEnabled = true backgroundJobServerPollIntervalInSeconds = 75 backgroundJobServerDeleteSucceededJobsAfterInHours = 24 backgroundJobServerPermanentlyDeleteDeletedJobsAfterInHours = 1
已知队列延迟可能由无可用工作线程导致,但调度状态到入队状态的转换延迟的可能原因有哪些?
可能的原因分析
1. 调度器轮询线程阻塞或实际间隔超标
你配置的backgroundJobServerPollIntervalInSeconds = 75,正常情况下调度器每75秒扫描一次Redis中的待触发任务,最多延迟75秒。但如果调度器线程被阻塞——比如Redis连接超时、锁竞争、其他耗时操作占用线程,实际扫描间隔会远超配置值,直接导致任务延迟入队。可以查看应用服务器的线程栈,确认调度器线程是否处于阻塞状态。
2. 应用服务器与Redis时钟不同步
Jobrunr依赖应用服务器和Redis的时钟一致性判断任务触发时间。如果Redis服务器时钟比应用服务器慢几小时,应用服务器会认为任务还未到调度时间,进而延迟入队。需要核对两台服务器的系统时间和时区,确保完全对齐。
3. 重试退避策略配置/实现错误
你设置的backOffPolicyTimeSeed = 6,Jobrunr默认采用指数退避,公式为退避时间 = 6 * (重试次数²)(单位:秒)。按此计算,第1次重试应在失败后6秒调度,第2次为24秒,但你的时间线间隔达数小时,明显不符合预期。可能是自定义退避策略时错误设置了时间单位(把秒写成小时),或是业务代码手动篡改了重试调度时间。
4. Redis键空间通知未配置
Jobrunr的Redis存储可通过键空间通知替代轮询,任务到时间会立即触发入队。如果Redis未开启notify-keyspace-events = Ex(过期事件通知),Jobrunr只能依赖轮询,一旦轮询出现问题就会导致延迟。需检查Redis配置中的该参数是否正确开启。
5. 任务元数据时间戳异常
直接查看Redis中重试任务的元数据,确认scheduleAt字段的时间戳是否正确。如果任务失败时该时间戳被错误设置为几小时后,任务自然会延迟入队。这可能是Jobrunr重试逻辑出现异常,或是业务代码手动设置了错误的重试时间。
内容的提问来源于stack exchange,提问作者CarlosSM

