Skip to content

v1.7.2 — 自动化不再「一跑跑一天」

Choose a tag to compare

@XDTrees XDTrees released this 29 Sep 03:47
· 57 commits to main since this release

定好几点跑,就几点跑。之前是定好几点跑,然后从那一刻起每个整点都跑,跑到你睡觉。

你会看到:把签到配成 9 点,它 9 点跑了;然后 10 点又跑、11 点又跑、13 点、14 点、15 点……每个整点准时跑一次,一直跑到第二天零点。配了 [9] 的签到,一天能跑 8 次。猫猫旅行同理,满勤。

最诡异的是有的任务正常、有的不正常:活跃上报配的是 10 点,它就老老实实只跑一次。同样的代码、同样的时刻、同样的配置格式,凭什么它就能安分?

为什么:一个字段被当成两种意思用了。

闸门那边问的是「配置的那个小时花掉了没」——比如签到的 9 点,它去找的记号是 今天的9点。而跑完之后记账那边写的是「现在几点」——10 点 35 分跑完,写的就是 今天的10点。

两边的答案几乎永远对不上。于是闸门永远是开的,任务每小时都能再跑一次。至于为什么最后变成「每个整点一次」而不是每分钟一次——还有一道「同一小时内不许重复」的节流挡着,所以最密也就是每小时一发。

那个「正常」的任务恰恰是证据:上报配的是 10 点,而那次补跑碰巧发生在 10 点 35 分(同一小时内),它写下的记号正好是闸门要找的那个,于是就锁住了。纯粹是撞上的——换任何一个别的时刻,它照样失控。

还有两个更隐蔽的变体,即使在正确的时间点触发也会失效:

  • 一天跑两次的任务(猫猫旅行配 [9, 21]):字段只有一个,存不下两个时间点。晚上 21 点跑完写下 21,早上那个 9 的记号就被顶掉了——于是它又「欠着」,22 点、23 点接着跑;
  • 跑得久的任务:记的是跑完那一刻。11:58 开始、12:01 结束,就记成了 12 点——哪怕它是准时触发的。

怎么修的:把「花掉的时间点」和「什么时候跑的」彻底拆开,而且花掉的时间点用集合记(因为一天可能有好几个)。

  • 闸门改成只认「被花掉的那个配置小时」,一次一个,最早优先;
  • 节流(同一小时不重复)改用单独的字段,不再和记账混在一起;
  • 手动点「立即运行」不再吃掉当天的排期——它是「额外再跑一次」,不是「今天就算完事了」。所以 10 点 35 分按一下按钮,不会把晚上 21 点的猫猫旅行取消掉。

顺手修了一个让我很惭愧的地方:卡片一直瞒着我们

这次的问题本该一眼看出来,但卡片上每个任务只显示日期:

每日签到   09:00    2026-09-28 · 2

那个 2026-09-28 是日期,不是时刻。所以一天跑 1 次还是 8 次,卡片上是同一句话——肉眼看不出任何区别,只能去翻日志才发现。这就是它能活这么久的原因。

修复:卡片改显示真实运行时刻(用的是本来就采集、本来就传输、就是没渲染的那个 lastRunAtMs)。数据链路一直是通的,就差最后打印出来那一步。

还没有做的(说清楚,免得以为都好了)

运行记录仍然不落盘,重启后当天「已跑过」的记忆会清空。所以如果你在 15:00 重启一次,已经跑过的 9/10/11 点会被认为「还没跑」,补跑一轮——这是刻意保留的补跑设计(笔记本睡过 10 点,醒来当天仍要跑),不是 bug。但它意味着「重启几次就补跑几次」,这点没有改变。

真要连这个也记住,得把「花掉的时间点」和收益账本一样持久化。这次没做,因为补跑本身是对的、而每次重启补跑一轮的代价是可接受的(任务都是幂等的);把它一起改了反而会让「睡过头当天不跑」。先说明白,不夹带。

验证

  • 类型检查全绿,测试 259 项全绿(原 248 + 新增 11)。
  • 新增 tests/automation-schedule.test.ts 锁住四个场景:补跑后当日不再重复、一天两次的任务各跑一次且中间安静、跨整点仍记在被消耗的那个时间点上、手动运行不吃掉当天排期。
  • 反向验证:把修复完整撤回成原始写法后,这 5 个关键用例全部变红(含「每整点重复执行」那条)——确认测试确实能抓住这个 bug,而不是闭着眼睛也绿。