文档:开发计划 §10.6 回写死锁重试后补(43cf2a1)执行记录
This commit is contained in:
@@ -1511,6 +1511,27 @@ sqlite 无 gap lock,故该分支由 `tests/test_convert_core.py` 用注入点
|
||||
|
||||
> 已恢复全部突变,`grep -rn "MUTATION\|1 = 1" app/ tests/ scripts/` **无残留**。
|
||||
|
||||
### 10.6 T-13 后补:死锁 1213 服务端自动重试(2026-09-10 同日用户拍板 · 已落地 `43cf2a1`)
|
||||
|
||||
§10.2 遗留的「服务端是否应重试死锁」已拍板:**服务端在数据访问层自动重试**(依据:Oracle MySQL 官方博客
|
||||
错误码表 1213 = "Retry the entire transaction")。
|
||||
|
||||
**改动**(`app/gateway/convert_core_repository.py` + `app/config/settings.py`):
|
||||
- `apply_convert` 改为重试外壳 + `_apply_convert_once` 事务体:死锁方被整体回滚、库内零残留,
|
||||
重跑即重新读库(满足「重试前重新取数」);
|
||||
- 只重试 **1213**(`_is_deadlock` 取底层 DBAPI `orig.args[0]` 判定);**1205 不在范围**
|
||||
(其重试语义受 `innodb_rollback_on_timeout` 影响,官方口径为「默认重试语句」,与整事务重试不通用);
|
||||
- 阈值走 settings:`convert_deadlock_retry_max=2` / `convert_deadlock_retry_base_ms=50`,
|
||||
退避 = base·2^(n-1) + [0, base) 随机抖动(架构 §11「阈值不得硬编码」);
|
||||
- 重试安全:单事务回滚零残留 + 幂等锚点 `out_trade_id` 在 service 层不受影响。
|
||||
|
||||
**验证**
|
||||
- sqlite 单测 +3:重试后落库成功(调 3 次、退避递增)/ 预算耗尽上抛(零残留)/ 1205 不重试;
|
||||
- **突变 2 组精准命中后恢复**:① `_is_deadlock` 恒 False → 重试用例红;② 预算判断 `>=`→`>` → 耗尽用例红;
|
||||
- 全量 `pytest -q` → **739 passed / 10 skipped**(+3);
|
||||
- `CONVERT_STRESS=1` 并发 **9 passed**;**8 客户并发实测 1213×4 → 服务端重试全部第 1 次收敛、外部兜底 0 次**;
|
||||
- 真库脚本复跑零回归:apply **24/24** / service **35/35**。
|
||||
|
||||
---
|
||||
|
||||
## 11. 测试增量与基线预测
|
||||
|
||||
Reference in New Issue
Block a user