fix(engine): 错过任务检测漏查时间规则,00:00 任务永远触发不到 - #46
Open
AmberCXX wants to merge 2 commits into
Open
Conversation
scheduleOrigin 建定时器时只过 canScheduleToday(仅查 start_date/end_date), 未过 shouldFire,导致两个问题: 1. weekdays/days/months 不参与判定——「每周日」的任务会在周六被 报成「今天错过」 2. delay <= 0 一律落进 missed 分支——午夜重排本身发生在 00:00, 重排那一刻就把 00:00 的格子算成已过去,该时段任务永远跑不到 修法: - 新增 FIRE_GRACE_MS(90s)宽限支,刚过点的任务立即补触发而非报错过 - missed 与宽限两支都补 shouldFire(entry) shouldFire 改为 export 以便测试,并补 3 个回归测试。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016fd3qWDATPyaLxwM8s1Ag9
错过判定原本只看两样:delay 落在 MISSED_WINDOW_MS(2h) 内,以及 shouldFire 的排期规则。它从不查该条目今天是否已经触发过——fire() 只写 global.json 的 last_fire / last_sender / today_count 这类全局标量,回答不了「这一条今天跑没跑」。 于是任务时刻之后 2 小时内的任何一次重排,都会把已经跑完的任务重新报一遍: 启动、配置热加载的部分重排,以及午夜重排在边界上提前几毫秒跑到前一天时 (此时 22:00 的 delay 约为 -1h59m,正落在窗口里)。2026-08-22 / 08-23 / 08-28 / 08-29 连续复发,每次都要人工判真假,判错的代价是重复推送或漏跑。 改动:新增 per-entry 的已触发记录(forge-state/fires.json) - fireKey(entry) 来源文件 + 时刻 + 名字(缺省回退 sender)作稳定标识 - hasFiredToday(state, entry, today) 纯函数,state 由调用方注入 - markFired(state, entry, today) 返回新 state,并清掉非当天的键,文件不增长 - fire() 成功推送后落一条记录;scheduleOrigin 每次重排只读一次状态文件 - 错过分支追加 !hasFiredToday(...) 真实的漏跑不受影响:engine 当时没跑就没有记录,照常上报。 验证:forge-engine 28 tests 全过(新增 6 条覆盖键稳定性、label 缺省回退、 跨日失效、清理旧键、同日幂等);bunx tsc --noEmit 无错; bun hub-test-harness/harness.ts 8/8;fh hub self-test 8/8。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EWhZ8wD8Ne5yiYaCdL6cjf
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
动机
生产环境观察到两个现象:
[错过的任务]通知,但该任务当天根本不该跑根因是同一处:
scheduleOrigin()建定时器时走canScheduleToday(),而它只查start_date/end_date;完整时间规则在shouldFire()里,只在fire()时才调用(scheduler.ts:241)。于是排期阶段:
delay <= 0一律进 missed → 午夜重排在 00:00 跑时,target - now恰为负,00:00 的格子被自己判成已过去改动概要
forge-engine/scheduler.tsFIRE_GRACE_MS = 90 * 1000scheduleOrigin()增加宽限支:delay落在(-FIRE_GRACE_MS, 0]且通过shouldFire()→ 立即补触发(1s 后),计入 count,不报错过&& shouldFire(entry)shouldFire改为export(仅为可测性,无行为变化)forge-engine/scheduler.test.ts影响范围
forge-engine排期路径,不涉及 hub-server / 通道 / 审批FIRE_GRACE_MS取 90s 是保守值:足以覆盖午夜重排与冷启动的秒级偏差,又远小于最密的任务间隔(本地为 1 小时)。如需可配我可以改成常量导出或读 configself-test 结果
安全自检
无私人 ID / 密钥;测试用例不含真实 sender_id。
未覆盖
FIRE_GRACE_MS那条宽限支没有专门的单元测试——它在scheduleOrigin()内,需要 mockServer才能测。本地是通过日志验证的:把某任务从 00:00 改到 22:00 后重排显示排定 1,而同一任务在 00:00 时显示排定 0。如果你希望补这个测试,告诉我要不要把scheduleOrigin拆得更可测,我再提一版。🤖 Generated with Claude Code
https://claude.ai/code/session_016fd3qWDATPyaLxwM8s1Ag9