fix(auto-exchange): 「当天已兑」标记持久化到 app_config,防非0点重启重复补扫 #223

Merged
guke merged 2 commits from fix/auto-exchange-restart-resweep into main 2026-08-06 18:48:42 +08:00
Member

概览
把 0 点自动兑金币 worker 的「当天是否已兑」判定,从内存变量 last_run 改为持久化到 app_config(key auto_exchange.last_run_date)。修掉「进程重启即忘 → 每次非 0 点部署都全量补扫、把 0 点后才达标用户在非 0 点兑现金」的 bug。改 1 个实现文件 + 1 个文档 + 新增 1 个测试(+171 / −11)。

概览 把 0 点自动兑金币 worker 的「当天是否已兑」判定,从内存变量 last_run 改为持久化到 app_config(key auto_exchange.last_run_date)。修掉「进程重启即忘 → 每次非 0 点部署都全量补扫、把 0 点后才达标用户在非 0 点兑现金」的 bug。改 1 个实现文件 + 1 个文档 + 新增 1 个测试(+171 / −11)。
guke added 2 commits 2026-08-06 17:55:57 +08:00
worker 原用内存变量 last_run 记当天是否已兑,进程重启即归零;叠加「启动首轮无条件跑」,
导致每次非 0 点部署/重启都全量补扫一遍,把 0 点后才达标的用户(0 点是零头、白天攒够;
或 0 点后才赚到金币)在非 0 点兑成现金——即用户反馈的「非 0 点也出现金币转现金记录」。

改为把「上次成功兑换的北京日」持久化到 app_config(key=auto_exchange.last_run_date,仿
compare_alert 水位范式):当天已兑则同一北京日内重启/部署整轮跳过,不再补扫;真漏了 0 点
(标记<今天,如服务器宕机)才补跑一轮,保留原 Persistent 补跑语义。逐用户幂等保留做兜底。

新增 tests/test_daily_auto_exchange.py:首轮兑换+落库标记、同日重启不重复补扫(回归)、跨天补跑。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Author
Member

🤖 review-pr 深审结论

🟢 低风险 · 置信度 0.9 — 钱相关 bug 的修复设计稳、契约核对通过、关键场景测试全绿,可直接合。

净改动:把 0 点自动兑金币 worker 的「当天已兑」判定从内存 last_run 改成持久化到 app_config(key auto_exchange.last_run_date),修「进程重启即忘 → 每次非 0 点部署都全量补扫、把 0 点后才达标用户在非 0 点兑成现金」的 bug。

构建/测试状态(已实跑)

  • 铁律1 契约核对AppConfig.key 是主键(db.get(AppConfig, key) 成立);value 是 JSON/JSONB 列(存 ISO 日期字符串会当 JSON 标量存/读回 strdate.fromisoformat round-trip 正常,且 _read_last_runtry/except 兜脏值);updated_by_admin_id 可空;rewards.cn_today() 返回 date(与标记比较口径一致)。内部状态 key 不进 CONFIG_DEFS,与 compare_alert 水位同套路。合并 origin/main 干净。
  • 铁律2 实跑:venv pytest tests/test_daily_auto_exchange.py —— 3/3 通过first_run_converts_and_records_marker / same_day_restart_does_not_resweepbug 核心)/ new_day_runs_again(补跑)。

问题

  • 无。

正面

  • 标记写在 daily_auto_exchange 之后:中途崩则标记仍旧值 → 下次重跑,逐用户幂等 _has_exchange_in_on 跳过已兑、补完剩下 → 不双兑(钱安全的关键顺序)。
  • 保留「真漏 0 点」补跑语义(标记 < today 仍补),且只限罕见场景,非常态。
  • 文件锁(同机多进程互斥)+ 逐用户幂等双保险防并发 TOCTOU。
  • 3 个测试正好覆盖首跑 / 同日重启不重扫 / 跨日再跑三大关键路径。

建议

  • 无。

只读深审 · worktree 合并 origin/main(干净)+ 实跑 venv pytest(3/3)

## 🤖 review-pr 深审结论 🟢 **低风险** · 置信度 0.9 — 钱相关 bug 的修复设计稳、契约核对通过、关键场景测试全绿,可直接合。 **净改动**:把 0 点自动兑金币 worker 的「当天已兑」判定从**内存 `last_run`** 改成**持久化到 `app_config`**(key `auto_exchange.last_run_date`),修「进程重启即忘 → 每次非 0 点部署都全量补扫、把 0 点后才达标用户在**非 0 点**兑成现金」的 bug。 ### 构建/测试状态(已实跑) - **铁律1 契约核对**:`AppConfig.key` 是主键(`db.get(AppConfig, key)` 成立);`value` 是 JSON/JSONB 列(存 ISO 日期字符串会当 JSON 标量存/读回 `str`,`date.fromisoformat` round-trip 正常,且 `_read_last_run` 有 `try/except` 兜脏值);`updated_by_admin_id` 可空;`rewards.cn_today()` 返回 `date`(与标记比较口径一致)。内部状态 key 不进 `CONFIG_DEFS`,与 compare_alert 水位同套路。合并 `origin/main` 干净。 - **铁律2 实跑**:venv `pytest tests/test_daily_auto_exchange.py` —— **3/3 通过**:`first_run_converts_and_records_marker` / `same_day_restart_does_not_resweep`(**bug 核心**)/ `new_day_runs_again`(补跑)。 ### 问题 - 无。 ### 正面 - **标记写在 `daily_auto_exchange` 之后**:中途崩则标记仍旧值 → 下次重跑,逐用户幂等 `_has_exchange_in_on` 跳过已兑、补完剩下 → **不双兑**(钱安全的关键顺序)。 - 保留「真漏 0 点」补跑语义(标记 `< today` 仍补),且只限罕见场景,非常态。 - 文件锁(同机多进程互斥)+ 逐用户幂等双保险防并发 TOCTOU。 - 3 个测试正好覆盖首跑 / 同日重启不重扫 / 跨日再跑三大关键路径。 ### 建议 - 无。 <sub>只读深审 · worktree 合并 origin/main(干净)+ 实跑 venv pytest(3/3)</sub>
guke merged commit a6b660486f into main 2026-08-06 18:48:42 +08:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: WonderableAI/shaguabijia-app-server#223