Files
shaguabijia-app-server/deploy/daily-exchange.md
T
ouzhou 57ddcd356b feat(wallet): 0 点定时把用户金币「到分全额」自动兑成现金 (#45)
客户端已删手动兑入口、改「0 点自动兑现金」,服务端补这条批处理:
- wallet.exchange_coins_to_cash 加 remark / enforce_min 参数:enforce_min=False(自动兑)只要够
  1 分(COIN_PER_CENT)即可,不受手动兑下限约束;remark 可定制。
- 新增 wallet.daily_auto_exchange(db):扫 coin_balance>=100 的用户,到分全额(floor(余额/100)*100)
  兑现金,零头留下次;幂等键=当天是否已有 exchange_in 流水(_has_exchange_in_on);逐用户独立事务,
  单用户异常 rollback 不中断。
- scripts/daily_auto_exchange.py(--once / --loop):带 .env AUTO_EXCHANGE_ENABLED 开关(false→no-op)
  + 文件锁防重入;deploy/ 配 systemd service+timer(0 点触发)+ 说明。
- config.AUTO_EXCHANGE_ENABLED(默认 true)+ .env.example。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: OuYingJun1024 <1034284404@qq.com>
Reviewed-on: #45
Co-authored-by: ouzhou <ouzhou@wonderable.ai>
Co-committed-by: ouzhou <ouzhou@wonderable.ai>
2026-06-11 23:36:26 +08:00

60 lines
2.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 0 点自动兑金币 定时任务 — 运维手册
> 对象:维护「每天 0 点把用户金币自动兑成现金」这套定时任务的同事。
> 🔒 服务器登录信息见**私密交接清单**,不入库。
## 它是什么
客户端已删手动「兑金币」入口、改为「0 点自动兑现金(可能存在延迟)」,故服务端每天 0 点跑一轮:
把每个用户的金币按汇率 **100 金币 = 1 分** 兑成现金。
- **到分全额**:`coin_amount = floor(余额 / 100) × 100`,不足 1 分(<100 金币)的零头留到下次。
- **复用 `exchange_in` 流水类型**(手动兑入口已下线,不会混淆),用户在「现金明细」看到「金币兑换现金」。
- **幂等**:同一用户当天已有 `exchange_in` 流水则跳过 → timer 重触发 / 手动重跑当天不会重复兑。
- 逻辑见 `app/repositories/wallet.py::daily_auto_exchange`,入口 `scripts/daily_auto_exchange.py`
## 文件
| 项 | 路径 |
|---|---|
| 脚本入口 | `scripts/daily_auto_exchange.py` |
| 核心逻辑 | `app/repositories/wallet.py::daily_auto_exchange` |
| 开关 | `.env``AUTO_EXCHANGE_ENABLED`(默认 true;false=脚本 no-op) |
| systemd 单元 | `deploy/daily-exchange.{service,timer}` |
| 运行锁 | `/tmp/daily_auto_exchange.lock`(可用环境变量 `DAILY_EXCHANGE_LOCK` 覆盖) |
## 部署(Linux 服务器)
```bash
sudo cp deploy/daily-exchange.{service,timer} /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable --now daily-exchange.timer
systemctl list-timers daily-exchange.timer # 确认下次触发时间
```
## 本机 Windows 开发(无 systemd)
直接手动跑:
```
.venv\Scripts\python -m scripts.daily_auto_exchange --once
# 本地循环调试(每小时一轮,幂等空跑无害):
.venv\Scripts\python -m scripts.daily_auto_exchange --loop --interval 3600
```
## 怎么看健康 / 手动跑一次
```bash
sudo systemctl start daily-exchange.service # 立即手动跑一轮(不等 0 点)
journalctl -u daily-exchange -n 30 --no-pager # 看日志:扫描/兑换/跳过/失败/累计兑入分
```
日志一行形如:`自动兑完成 用时1.2s 扫描120 兑换88 已兑过跳过30 零头跳过2 失败0 累计兑入15600分`
## 怎么关 / 临时停
- **临时停(推荐)**:`.env``AUTO_EXCHANGE_ENABLED=false` → 脚本 no-op,无需动 timer。
- **停 timer**:`sudo systemctl disable --now daily-exchange.timer`
## 脚本参数
- `--once`:跑一轮(timer 用这个,默认)
- `--loop --interval N`:常驻循环,每 N 秒一轮(默认 3600,调试用)
- 锁位置可用环境变量 `DAILY_EXCHANGE_LOCK=/path/to.lock` 覆盖
## 注意事项
- **触发时间**:`OnCalendar=*-*-* 00:00:00`。客户端文案已注明「可能存在延迟」,要错开整点扎堆可改 `00:05:00`
- **catch-up**:`Persistent=true`,服务器宕机错过当天会在重启后补跑一轮。
- **DB 无关**:sqlite / postgres 均可(不像美团 ETL 需要 PG)。
- **改脚本 / 改部署**:走 git + PR,由有 root 的人部署。