分析与解决方案:backend/src/schedules.rs 的 run 函数中的 Err(AppError::Busy) 问题
问题所在
在 backend/src/schedules.rs 文件的 run 函数中,当遇到 Err(AppError::Busy) 错误时,目前的处理方式是将 next_run_at 设置为 now + BUSY_RETRY_MS,而不是保留原始的 due 值。这种做法导致后续的 following() 函数继续使用这个被修改过的值,从而造成每次执行任务时都存在相同的偏差。
行为描述
具体的行为表现如下:
- 新建一个计划任务,首次执行时间为 10:00,间隔设置为 60 分钟。
- 在 10:00 时,人为使队列达到满载状态,模拟繁忙状态。
- 当队列恢复后,计划任务试图在 10:01 执行。
- 由于
next_run_at被错误地设置为now + BUSY_RETRY_MS,后续的执行时间依次变为 11:01、12:01,而不是预期的 11:00、12:00。
附带问题
另一个问题是 request_key 中包含了 due 字段,而在重试时 key 发生了变化。这与注释中提到的“重试同一个槽位”相矛盾,因为键的变化意味着任务可能被分配到了不同的槽位。
解决方案与建议
为了解决这个问题,建议采取以下措施:
- 仅延迟本次触发:当遇到
Err(AppError::Busy)错误时,应该只延迟本次任务的触发,而不是影响后续的所有执行计划。 - 单独保存重试时间:可以引入一个新的字段来单独保存重试的时间,这样即使任务因为繁忙而重试,也不会影响到原本的执行计划。
- 按原始
due计算下一槽位:在任务成功执行后,应该根据原始的due值来计算下一个执行槽位,确保执行时间的准确性。
此外,建议补充针对 Busy 路径的测试,以确保上述修改能够正确地解决偏差问题,并验证 request_key 在重试时是否保持不变,以符合“重试同一个槽位”的设计要求。
测试建议
- 测试在繁忙状态下创建的任务是否会正确地按照原始计划执行。
- 验证在任务重试时,
request_key是否保持不变,确保任务仍然在同一个槽位执行。 - 确认任务在成功执行后,后续的执行时间是否按照原始的
due值来计算。
通过这些测试,可以确保修改后的代码能够满足需求,并解决当前存在的问题。
评论已关闭