|
|
@@ -1,7 +1,7 @@
|
|
|
# 启动期数据库连接竞态根治执行任务书
|
|
|
|
|
|
> **文档用途**:给**其他大模型 / 编码代理**照着执行。根因已于 2026-09-26 复现并三层取证完毕,**禁止再把它当成「MySQL 权限不足」或「SqlSugar 连接泄漏」去排查**。
|
|
|
-> **状态**:**全部完成(2026-09-26 23:49)**。火忘 `Task.Run` 已撤回为同步调用;5 次冷启动全部成功且竞态报错归零;`JobSchedule:Enabled` 已恢复 `true` 并复验一次仍干净(246.3s,竞态 0,未处理异常 0);守卫测试已补且验证过能拦住回归。后端版本 `1.0.571`(rebase 到远端 `1.0.570` 之上,故为 1.0.571 而非原计划的 1.0.581)。端口开放延迟实测约 160~200 秒(不含编译),超过建议阈值,是否改走方案 A1 仍待负责人定,但不阻塞本次收口。
|
|
|
+> **状态**:**全部完成(2026-09-26 23:49)**。火忘 `Task.Run` 已撤回为同步调用;5 次冷启动全部成功且竞态报错归零;`JobSchedule:Enabled` 已恢复 `true` 并复验一次仍干净(246.3s,竞态 0,未处理异常 0);守卫测试已补且验证过能拦住回归。后端版本 `1.0.571`(rebase 到远端 `1.0.570` 之上,故为 1.0.571 而非原计划的 1.0.581)。<br>**2026-09-27 补测并收口**:端口开放实测 229.1 秒,其中 CodeFirst `InitTables` 148s、`MdpSchemaAligner` 仅 38s;**方案 A1 已放弃**,包 R 按同步定稿(见 §4.1)。同次实测查出并修复了一个独立缺陷 `cancel_requested_flag` 残留 NULL(`1.0.581`,见 §4.2)。
|
|
|
> **问题背景与完整证据**:[`20260926问题描述.md`](20260926问题描述.md),尤其第七节「复核结论与证据」。
|
|
|
> **创建日期**:2026-09-26
|
|
|
> **适用范围**:本机 `dotnet run` 连远程库 `123.60.180.165:3306/aidopdev`。本问题**只存在于当前工作区**,HEAD 主线不受影响(见 §1.2)。
|
|
|
@@ -13,7 +13,7 @@
|
|
|
|---|---|---|
|
|
|
| R 主修:撤回火忘任务 | **已完成(2026-09-26 22:24)** | `AiDOP/Startup.cs` 的火忘 `Task.Run` 已换回同步调用;三处必须保留的未提交改动(`AidopOutboundOptions`、两个 `AddHostedService`)未动 |
|
|
|
| V 验证:连起 5 次 + 竞态归零 | **已完成(2026-09-26 22:46)** | 5/5 `listen=True`,`race=0`,`fatal=0`。耗时 232.4 / 242.2 / 206.1 / 204.6 / 201.0 秒。对齐结果与修复前一致:`mdp_source_table_registry` 53 行;`mdp_std_inv_trans` DB_SYNC 594230;`mdp_std_inventory` DB_SYNC 103600 / SEED 5;`mdp_std_item` DB_SYNC 49803 / PLATFORM_FORM 22091 |
|
|
|
-| M 实测:端口开放延迟 | **已完成,但口径要读批注** | 上面 5 个数字**含编译**(脚本按任务书原文每次都带编译,且重定向把输出缓冲到进程退出,无法从日志里拆出编译段)。编译本身约 40 秒(宿主进程在 `dotnet run` 之后约 40 秒才出现),故纯启动延迟约 **160~200 秒**,**超过 §4 建议的 60 秒阈值**。是否改走方案 A1 由负责人定 |
|
|
|
+| M 实测:端口开放延迟 | **已完成并已结论** | 2026-09-27 用端口探针重测(`--no-build`):**229.1 秒**,其中 CodeFirst `InitTables` 148s(65%)、`MdpSchemaAligner` 38s(17%)。**方案 A1 已放弃**——它只能省下那 17%,够不到 60 秒阈值,却把刚焊死的并发口子重新打开。分段数据与理由见 §4.1 |
|
|
|
| S 守卫:补回归测试 | **已完成** | `Infrastructure/StartupConcurrencyGuardTests.cs` 通过;临时贴回 `Task.Run` 探针后该测试确实变红,探针已撤回 |
|
|
|
| X 收口:App.json 提交风险 | **已完成(2026-09-26 23:49)** | `JobSchedule:Enabled` 恢复为 `true`。同文件的 `AiDOP:Jobs:Enabled=false`、`Outbound:Enabled=false`、`MdpRebuild` 各项属 165 治理既定决策,未动。恢复后复验一次:listen=True,246.3s,竞态 0,未处理异常 0 |
|
|
|
| P 可选:ApprovalFlow 容错 | **不需要** | 包 V 已全绿且竞态归零,按 §7 第 1 条本包不做 |
|
|
|
@@ -216,6 +216,41 @@ SELECT TABLE_NAME, COLUMN_NAME FROM information_schema.COLUMNS
|
|
|
- 延迟可接受(由负责人定阈值,建议 ≤ 60s)→ **包 R 定稿**,任务书收口;
|
|
|
- 延迟不可接受 → 退回问题描述文档的**方案 A1**:把这段改为订阅 `IHostApplicationLifetime.ApplicationStarted` 后再执行。注意 A1 仍需过一遍包 V 的 5 次验证,因为它只是把窗口挪开,没有消除共享上下文。
|
|
|
|
|
|
+### 4.1 实测结果与结论(2026-09-27 00:36,**方案 A1 已放弃**)
|
|
|
+
|
|
|
+按端口探针重测一次(`--no-build`,编译 52 秒单独计时并排除):进程启动 `00:36:16.2` → 5005 可连 `00:40:05.4`,**229.1 秒**。分段:
|
|
|
+
|
|
|
+| 区间 | 耗时 | 内容 | 证据 |
|
|
|
+|---|---|---|---|
|
|
|
+| +0 → +5s | 5s | 运行时 / Host 引导 | 首条日志 `00:36:21.1` |
|
|
|
+| +5 → +153s | **148s(65%)** | SqlSugar CodeFirst `InitTables` 逐个对齐 285 个实体 | `初始化表结构 ... (1300000000001 - 001/285)` 数到 `285/285`,其间几乎无日志 |
|
|
|
+| +153 → +160s | 7s | `AutoVersionUpdate` + TaskQueue / Schedule 起服务 | `00:38:55.9 AutoVersionUpdate 中间件运行` |
|
|
|
+| +160 → +198s | **38s(17%)** | `MdpSchemaAligner` 来源登记 | 对齐日志 `00:38:56` → `00:39:34`,44 行 |
|
|
|
+| +198 → +229s | 31s | 其余 Configure(S8 规则供给、菜单同步、ApprovalFlow `InitTables` + 模板种子)+ Kestrel 绑定 | 端口探针 `00:40:05.4` |
|
|
|
+
|
|
|
+**结论:不采用 A1,包 R 按现状(同步)定稿。** 理由:
|
|
|
+
|
|
|
+1. **A1 解决不了被问的那个问题。** 挪走对齐只能把 229s 压到约 191s,§4 建议的 60 秒阈值照样够不着。延迟的主因是那 148 秒的 CodeFirst,不是对齐器,这个决策点本身是伪命题。
|
|
|
+2. **代价换来的是同一类风险。** `ApplicationStarted` 确实比 Configure 里 `Task.Run` 安全(那时 Configure 已跑完,不再撞 ApprovalFlow 的无容错 `InitTables`),但那一刻 `ModuleRebuildJobStore` 轮询、`EtlInstanceRegistrar` 心跳、`ScheduleService` 都已在后台运行,单例 `SqlSugarScope` 的 AsyncLocal 复用隐患仍在。为 17% 的收益重新打开刚焊死的门,不划算。
|
|
|
+3. **同步顺带保证一条不变量**:端口开放前 `source_system` / `written_by` 已对齐完。异步会出现一个窗口,期间监控页与证据页读到未对齐的数据 —— 那是正确性回退。
|
|
|
+
|
|
|
+**若确实要提速,该动的是那 148 秒**:本机开发环境把 `TableSettings:EnableInitTable` 置 `false`(`Database.json:43`,结构稳定后本地改、不提交),或本地指向本地 MySQL 而非云库(当前连的是远端主机,每实体一次元数据往返约 0.5 秒)。
|
|
|
+
|
|
|
+> **禁止**调大 `InitTableMaxDegreeOfParallelism`(现为 1,`Database.json:45`)。`SqlSugarSetup.cs:662` 的 `Parallel.ForEach` 捕获的是同一个 `dbProvider`,并行 DDL 就是本任务书刚修掉的那类连接复用,只是换了个入口。
|
|
|
+
|
|
|
+### 4.2 本次实测顺带查出的独立缺陷(已修,`1.0.581`)
|
|
|
+
|
|
|
+`ado_module_dashboard_rebuild_job.cancel_requested_flag` 的表结构初始化**每次启动都失败**:
|
|
|
+
|
|
|
+```
|
|
|
+[Sql]: alter table `ado_module_dashboard_rebuild_job` change column `cancel_requested_flag` `cancel_requested_flag` tinyint(1) NOT NULL
|
|
|
+SqlSugar.SqlSugarException: Invalid use of NULL value
|
|
|
+```
|
|
|
+
|
|
|
+成因:该列最早由 CodeFirst 建成可空无默认值,`1.0.580.sql` 的 `@col_exists` 判定为「已存在」而跳过了它本想建的 `NOT NULL DEFAULT 0`;实体属性是非空 `bool`,于是每次启动都尝试改 NOT NULL,撞上 44506 行中的 89 行 NULL。又因 `ContinueInitTableOnEntityFailure=true`(`Database.json:49`)被降级成 warning 跳过,这张表的结构一直是不完整的。
|
|
|
+
|
|
|
+已由 `UpdateScripts/1.0.581.sql` 回填 NULL→0 并把列收口为 `NOT NULL DEFAULT 0`;`1.0.581.verify.sql` 断言列不可空且零 NULL。开发库已执行:UPDATE 命中 89 行,verify 返回 1。
|
|
|
+
|
|
|
---
|
|
|
|
|
|
## 5. 包 S:补守卫测试(当前零防护)
|