Skip to content

新增:定时签到「随机前后 N 分钟」+「启动补签」开关 - #313

Closed
coulsontl wants to merge 1 commit into
aimod-cc:betafrom
coulsontl:feat/checkin-random-window
Closed

coulsontl wants to merge 1 commit into
aimod-cc:betafrom
coulsontl:feat/checkin-random-window

Conversation

@coulsontl

Copy link
Copy Markdown
Contributor

这个 PR 做了什么

给定时签到加「随机前后 N 分钟」,让每天的签到不再固定在同一分钟打上游;并加一个全局开关控制开机是否立即补签。

  • 条目级窗口:每条定时条目新增 jitterMinutes(0–120,缺省 0 = 行为不变)。窗口 = [时刻-N, 时刻+N],夹到当天 00:00–23:59。窗口起点由现有 30 秒轮询触发一次。
  • 账号级铺开:本轮内的每个账号在窗口内各自取一个时刻,按时间顺序串行执行。偏移用 sha256(条目 id | 日期 | 时刻 | N | 账号 id) 确定性派生 —— 同一天重试落在同一时刻,面板「下次执行」与真实行为一致,不需要额外的随机数状态。
  • 启动补签开关:autoCheckin.startupCatchUp,缺省 true(= 改造前行为)。关掉后启动只起调度循环,今天未执行的条目等到各自窗口起点再签,避免早上开机把当天的随机窗口提前签掉。
  • 窗口已过 / 窗口中途启动:偏移已过的账号立即执行 —— 这正是「错过窗口就全部立刻签完」的实现,不需要单独分支。

为什么这么设计

  • 铺开放在后台任务里,不在 tick 里 await:窗口最长 4 小时。占住 tick 会延后其他条目,占住全局执行锁会拒掉所有手动签到。后台任务只在每个账号执行的那几秒抢锁,账号之间的等待全程在锁外,按墙上时钟分段重算(休眠 / 改时钟都能自愈)。
  • 确定性偏移而不是每次重抽:面板展示的 nextRunAt 与真实执行时刻能对上,同一天重试也不会换时间。
  • run_checkin 抽出 run_account / summarize_results:定时铺开与批量路径共用同一段记账(落 checkinAt、签到记录台账、汇总口径),不存在两套行为;run_checkin 签名不变,手动路径零改动。手动签到(批量 / 单账号 / 条目「立即执行」)不铺开。

自审时修掉的问题

  • 窗口跨零点时,起点由「这一轮的日期」推出而不是「此刻的日期」—— 否则 23:5x 的窗口会算出次日同一分钟,所有账号白睡约 24 小时。
  • 铺开任务的目标解析与计划前移到 spawn 之前:解析失败时能回退 lastFiredDate 让下个 tick 重试,账号集合也在 spawn 时定格。
  • spreads 的 key 改由 SpreadGuard 的 Drop 清理,正常结束 / 提前 return / 后台任务被 abort 三种出口都覆盖。
  • acquire_running 加 10 分钟上限:另一轮签到若卡死在上游,无限等待会让铺开任务永久挂住、key 永不释放。
  • 本轮被提前截断(停机 / 等锁超时)时不落 lastFiredDate:剩下的账号今天还一次没签,落账会把它们整天静默掉。
  • jitterMinutes 的写入校验拒绝 1e3 / 十六进制 / 前后空格等 Number() 会放过的写法;前端 submit 加 canSave 守卫。

验证

  • cargo test -p agent2api-server:688 passed / 0 failed(含 19 个新增纯函数单测:窗口边界夹取、偏移确定性 / 范围 / 分散、触发判定、字段往返)
  • cargo check --all-targets 通过
  • node desktop-tauri/i18n/scan.mjs --check:所有语言的所有域无缺失键
  • 本地起 headless 服务端实测:窗口起点精确(08:30 ±60 → 07:30)、121 分钟被 400 拒绝、省略 jitterMinutes 时保留旧值、20 个账号在 180 分钟窗口内分散执行;截图确认「随机前后」数字输入与「启动补签」开关渲染正常

兼容性

  • jitterMinutes 缺省 0,存量配置行为完全不变(窗口就是时刻本身)。
  • 「启动补签」缺省开,存量用户升级后的表现与之前一致。
  • i18n 产物已按 scan.mjs → build.mjs → ui-islands build 重新生成并入库。

🤖 本条回复由 AI Agent 生成

…由 30 秒轮询触发一次,本轮账号在窗口内各自取一个确定性偏移依次执行;对上游呈现的是散在窗口里的逐个请求,而不是每天同一分钟的一串。偏移用 sha256(条目 id | 日期 | 时刻 | N | 账号 id) 派生,同一天重试落在同一时刻,面板「下次执行」与真实行为一致

2. 新增:「启动补签」全局开关(缺省开 = 保持改造前行为)—— 关掉后启动只起调度循环,今天未执行的条目等到各自窗口起点再由调度触发,避免早上开机把当天的随机窗口提前签掉
3. 优化:随机窗口的铺开走后台任务而非在 tick 里 await —— 窗口最长 4 小时,占住 tick 会延后其他条目,占住全局执行锁会拒掉所有手动签到;后台任务只在每个账号执行的几秒里抢锁,账号之间的等待全程在锁外,按墙上时钟分段重算(休眠 / 改时钟都能自愈)
4. 优化:`run_checkin` 抽出 `run_account` 与 `summarize_results`,定时铺开与批量路径共用同一段记账(落 checkinAt、签到记录台账、汇总口径),不存在两套行为;`run_checkin` 签名不变,手动路径零改动
5. 修复:随机窗口铺开的时间起点由「这一轮的日期」推出而不是「此刻的日期」—— 23:5x 的窗口跨过零点时,用现在的时间会算出次日同一分钟,所有账号要白睡约 24 小时
6. 修复(自审):铺开任务的目标解析与计划前移到 spawn 之前 —— 解析失败时能回退 `lastFiredDate` 并让下个 tick 重试,此前是一次偶发失败就让这条条目整天静默;账号集合也在 spawn 时定格,后台跑 4 小时期间账号增删不再让计划中途变形
7. 修复(自审):`spreads` 的 key 改由 `SpreadGuard` 的 Drop 清理 —— 正常结束 / 提前 return / 后台任务被 abort 三种出口都覆盖;此前只在正常路径手写清理,一次异常就让这条条目当天永久不再重试
8. 修复(自审):`acquire_running` 加 10 分钟上限 —— 另一轮签到若卡死在上游,无限等待会让铺开任务永久挂住、key 永不释放;到点如实跳过剩余账号
9. 修复(自审):本轮被提前截断(停机 / 等锁超时)时不落 `lastFiredDate` —— 剩下的账号今天还一次没签,落账会把它们整天静默掉;已签过的重试幂等
10. 修复(自审):`jitterMinutes` 的写入校验拒绝 `1e3` / 十六进制 / 前后空格等 `Number()` 会放过的写法;`submit` 加 `canSave` 守卫,回车与程序化点击也挡得住
11. 新增:19 个纯函数单测(窗口边界夹取、偏移确定性/范围/分散、触发判定、字段往返)
@coulsontl coulsontl closed this Oct 20, 2026
@coulsontl
coulsontl deleted the feat/checkin-random-window branch October 20, 2026 14:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant