From 8ef335a802fee0093f365fe925076d2b7b34b2ac Mon Sep 17 00:00:00 2001 From: k2safe Date: Sun, 20 Sep 2026 21:53:34 +0800 Subject: [PATCH] test: verify transaction retry metric in mysql integration --- docs/reports/phase-7-regression-status.md | 2 +- internal/storage/mysql/db_retry_integration_test.go | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/reports/phase-7-regression-status.md b/docs/reports/phase-7-regression-status.md index ad76595..42272e5 100644 --- a/docs/reports/phase-7-regression-status.md +++ b/docs/reports/phase-7-regression-status.md @@ -9,7 +9,7 @@ | 本地发布门禁统一入口 | 2026-09-20;`make release-local-check` | PASS;服务端、SDK、独立示例竞态测试、vet、build、当前协议门禁、146个 Markdown 本地链接和 SDK 独立依赖检查均通过;命令明确不替代真实 MySQL 集成与目标生产验收 | | 发布物静态身份清单 | 2026-09-20;`make release-manifest`;无 `ORBIT_MYSQL_DSN` | PASS;输出构建/协议身份及28条迁移名称与SHA-256校验和,未读取数据库、凭据或业务数据;目标库仍需单独执行 `orbit-admin verify` | | 发布物与管理二进制绑定校验 | 2026-09-20;`go test -race ./cmd/orbit-admin`;匹配/修改 revision/未知命令场景 | PASS;`verify --manifest` 在数据库连接前拒绝身份、协议或迁移校验和不一致的清单,匹配清单通过;不修改数据库 | -| 提交前事务死锁恢复 | `go test -race -run TestRetryableTransactionErrorOnlyMatchesPreCommitLockFailures ./internal/storage/mysql`;真实 MySQL `TestIntegrationWithTxRetriesPreCommitDeadlock` | PASS;两事务真实锁环触发 1213,失败事务仅在提交前按有界退避重试一次,最终两笔事务各提交一次;Begin/Commit 错误不重放,目标拓扑锁等待和死锁率仍需生产观测 | +| 提交前事务死锁恢复 | `go test -race -run TestRetryableTransactionErrorOnlyMatchesPreCommitLockFailures ./internal/storage/mysql`;真实 MySQL `TestIntegrationWithTxRetriesPreCommitDeadlock` | PASS;两事务真实锁环触发 1213,失败事务仅在提交前按有界退避重试一次,最终两笔事务各提交一次,且真实集成断言重试计数增长;Begin/Commit 错误不重放,目标拓扑锁等待和死锁率仍需生产观测 | | 提交前事务重试观测 | `internal/observability.TestRuntimeObservationDoesNotExposeErrors`;固定指标目录;`make release-local-check` | PASS;`orbit_db_transaction_retries_total` 与 `orbit_db_transaction_retry_exhausted_total` 以无标签固定计数器导出,重试只在退避成功后计数,提交回执不明不计入;目标拓扑告警阈值和跨节点聚合仍待生产验收 | | 就绪探针排空门控 | `go test -race ./internal/transport/httpserver ./cmd/orbit`;`TestReadinessEntersDrainBeforeShutdown` | PASS;SIGTERM 关闭路径先将 `/health/ready` 置为 503,再进入限定优雅关闭窗口;响应不泄露内部错误 | | 健康探针响应契约 | 2026-09-20;`go test ./internal/transport/httpserver && go test -race ./internal/transport/httpserver && make docs-check` | PASS;`/health/live` 与 `/health/ready` 返回 `Cache-Control: no-store`、`X-Content-Type-Options: nosniff`;未就绪和排空状态返回 `Retry-After: 1`,并由 HTTP 契约测试覆盖 | diff --git a/internal/storage/mysql/db_retry_integration_test.go b/internal/storage/mysql/db_retry_integration_test.go index 2574a5c..c0a38e4 100644 --- a/internal/storage/mysql/db_retry_integration_test.go +++ b/internal/storage/mysql/db_retry_integration_test.go @@ -33,6 +33,7 @@ func TestIntegrationWithTxRetriesPreCommitDeadlock(t *testing.T) { if _, err := db.ExecContext(ctx, "INSERT INTO orbit_test_tx_retry(id,value) VALUES (1,0),(2,0)"); err != nil { t.Fatal(err) } + beforeStats := ReadTransactionStats() var barrier sync.WaitGroup barrier.Add(2) @@ -71,6 +72,10 @@ func TestIntegrationWithTxRetriesPreCommitDeadlock(t *testing.T) { if callbackCalls.Load() < 3 { t.Fatalf("deadlock did not cause a bounded pre-commit retry; callback calls=%d", callbackCalls.Load()) } + afterStats := ReadTransactionStats() + if afterStats.Retries <= beforeStats.Retries { + t.Fatalf("transaction retry metric did not advance: before=%+v after=%+v", beforeStats, afterStats) + } var value int if err := db.QueryRowContext(ctx, "SELECT COALESCE(MIN(value),0) FROM orbit_test_tx_retry").Scan(&value); err != nil { t.Fatal(err) @@ -78,5 +83,5 @@ func TestIntegrationWithTxRetriesPreCommitDeadlock(t *testing.T) { if value != 2 { t.Fatalf("committed value=%d want 2", value) } - t.Logf("pre-commit deadlock recovered with %d callback attempts and two committed transactions", callbackCalls.Load()) + t.Logf("pre-commit deadlock recovered with %d callback attempts and transaction retry metric %+v", callbackCalls.Load(), afterStats) }