makecindy / makecindy/cindy

feat(scheduler): 支持启动时补跑停机期间错过的自动化任务

Open
#2,421 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
2.7k
Forks
395
Avg merge
21h 48m
Merged PRs (30d)
776

Description

## 来源

- 来源频道:Discord #功能建议
- 来源帖子:希望 Cindy 能帮我完成:自动化任务错过增加事后补跑
- 原帖链接:https://discord.com/channels/1524291334654132335/1535524181096276058/1535524181096276058
- 提问人显示名称:青川凝
- 脱敏问题摘要:用户每天需要运行一项自动化任务,但电脑开机时间不固定;希望 Cindy 启动后检查是否错过当天的计划时间,并自动补跑。
- 使用频率:每天

## 用户实际需求

用户不是要求固定延迟重试,而是希望自动化任务具备明确的“错过后补跑”策略:

- 任务仍按每天的计划时间运行;
- 如果计划时间到达时 Cindy 没有运行,则在下次启动后补跑;
- 不要求在原计划时间附近启动电脑;
- 该能力应由用户主动为任务开启。

## 已确认的当前行为

截至 2026-08-11,当前 Scheduler 不会在应用启动时补跑停机期间错过的自动化任务:

- Scheduler 启动时会加载 active 任务,并以当前时间重新计算 nextFireAt;
- recurring cron 会直接排到严格晚于当前时间的下一个时间点;
- interval 任务的旧计划若已经过期,会重新排为 now + intervalMs;
- 代码注释明确说明冷启动时“漏掉的不补发”;
- 运行期因并发限制而到点未执行的任务会继续排队,但这只适用于进程仍在运行的情况,不覆盖关机或 Cindy 未启动期间。

关键实现与测试:

- packages/maker-scheduler/src/engine/scheduler.ts:start() 启动归一、computeNextFireAt() 以及 due tick 逻辑;
- packages/maker-scheduler/src/__tests__/scheduler.test.ts:已有用例确认过去的 nextFireAt 会在启动时直接重排到未来,不产生补跑。

因此这是当前产品语义缺口,不是现有功能的使用咨询。

## 产品判断

建议新增每个自动化任务独立配置的“错过后处理”策略,并保持现有行为为默认值,避免升级后大量旧任务突然补跑。

建议优先级:P2。

## 建议的 MVP

### 1. 每任务补跑策略

首版提供两种策略:

- 跳过错过的运行:默认值,保持当前行为;
- 启动时补跑最近一次:Cindy 下次启动后,对最近一次错过的计划只执行一次。

首版不逐次回放所有错过的时间点,避免长时间离线后出现启动风暴和重复消耗。

### 2. 适用边界

- 优先覆盖 active 的 recurring cron 任务;
- paused、manual 任务不自动补跑;
- 被动 Scheduler 实例不执行补跑;
- interval recurring 和未执行 one-shot 的语义需要单独确认,不能静默套用 cron 规则。

### 3. 补跑后的排期

- 补跑不应吞掉下一次正常计划;
- recurring cron 补跑完成后,nextFireAt 仍指向下一个正常 cron 时间点;
- 补跑应进入正常 Run History,并明确标记为“启动补跑”或等价原因;
- 成功、失败和通知行为与普通自动触发保持一致。

### 4. 去重与资源保护

- 多实例共享数据库时,同一个错过的计划点只能由一个 active 实例认领;
- 复用现有 claimDueFire / CAS 语义或提供等价的持久化认领;
- 补跑必须进入现有并发闸门,不能绕过最大并发限制;
- Cindy 在补跑尚未结束时再次重启,不能重复执行同一计划点。

## 非目标

- 不在一次启动时回放全部历史遗漏;
- 不为 manual 任务增加隐式自动运行;
- 不把任务失败后的自动重试与“应用离线导致错过”混为同一策略;
- 不改变未主动开启补跑的存量任务行为。

## 仍需产品确认

1. “最近一次补跑”是否允许无限追溯,还是需要可配置的最大补跑窗口?
2. interval recurring 任务是否也支持最近一次补跑,还是仅从启动时间重新倒计时?
3. 从未执行的 one-shot 任务在过期后是否应补跑一次?
4. 补跑失败后是否按普通失败处理,还是允许在本次启动周期内自动重试?
5. UI 应在任务表单中展示简单开关,还是“跳过 / 补跑最近一次”的策略选择?

## 与现有 Issue / PR 的关系

本轮已检索 open/closed Issue 以及 open/closed/merged PR,未发现覆盖“Cindy 启动后补跑停机期间错过的自动化任务”的现有项。

相邻但不重复的能力包括自动化任务创建、模型配置、任务失败续跑以及 Codex Automations 导入;这些都没有改变冷启动跳过 missed run 的现有语义。

## 验收标准

- 默认策略保持现状,旧任务升级后不会自动补跑;
- 用户为每日 cron 任务开启“补跑最近一次”后,计划时间到达时 Cindy 未运行,下次启动会补跑一次;
- 离线跨过多个计划点时只补跑最近一次,不连续回放全部遗漏;
- 同一遗漏计划点在重复启动或多实例环境下只执行一次;
- 补跑遵守现有并发上限,资源不足时可排队但不丢失;
- paused、manual 和 passive Scheduler 不触发补跑;
- 补跑记录、状态、失败信息和通知在 Run History 中可辨认;
- 补跑后下一次正常 cron 排期保持正确。

Contributor guide

Open the contributing guide

Research direction

Start with packages/maker-scheduler/src/engine/scheduler.ts, especially start(), computeNextFireAt(), and the due-tick logic, then review packages/maker-scheduler/src/__tests__/scheduler.test.ts. Resolve the listed product questions before implementation; done means the acceptance criteria hold for cron catch-up, defaults, deduplication, concurrency, run history, and subsequent scheduling.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.