# DataDownload 代码审核复核与修复报告 > 初审日期:2026-09-19 > 复核及修复日期:2026-09-19 > 审核范围:当前 git 未提交改动,并结合当时的集成设计归档进行权限、FileRequest、生命周期和存储约束复核。当前文档入口见 [README.md](README.md)。 > 关联台账:[data-download-open-issues.md](../issues/data-download-open-issues.md) ## 1. 结论 原报告 11 条结论中:CR-02、CR-05、CR-06、CR-08 是实际问题;CR-04、CR-07、CR-10、CR-11 是低风险一致性或完整性问题;CR-01、CR-03、CR-09 不成立或没有足够证据。 本轮已经修复确认成立且适合在当前范围内处理的问题,并补充修复复核时发现的任务计数错误。CR-08 的 HTTP 下载内存放大已经解决,但 ZIP 构建、Renderer 首次生成和上游二进制读取仍属于 DD-010,不能标记为整体解决。 ## 2. 逐条复核与处理状态 | ID | 原严重度 | 复核结论 | 当前状态 | 处理结果 | |---|---|---|---|---| | CR-01 | 高 | 不成立 | rejected | 当前没有同 key 嵌套加锁;binary 与 rendered 分支互斥。不可重入只属于未来维护约束。 | | CR-02 | 高 | 成立 | resolved | 上游请求改用独立、自动续租的 FileRequest lease;content 锁仅覆盖提交阶段;等待者通过 Asynq 延迟重试。 | | CR-03 | 高 | 证据不足 | rejected | 短数组补 `nil` 与旧 PowerFlow 导出语义一致;新增测试固定该兼容行为。 | | CR-04 | 中 | 低风险类型不一致 | resolved | `run_status` 改用 `*int32`,超出 PostgreSQL integer 范围时显式报错。 | | CR-05 | 中 | 成立 | resolved | item 写入改为 `(taskId,itemKey)` upsert 并回填已有 `_id`;稳定队列 TaskID 冲突视为已调度。 | | CR-06 | 中 | 成立 | resolved | 清理时统一使用 `ExpiresAt + 30天`。 | | CR-07 | 中 | 字段未维护属实,影响被夸大 | resolved | Recount 统计空 TaskDocument,前端任务进度显示空文档数。 | | CR-08 | 中 | 成立 | partially resolved | Package、二进制文档、缓存 RenderArtifact 已流式响应;生成和打包阶段的内存问题继续由 DD-010 跟踪。 | | CR-09 | 中 | 不成立 | rejected | 设计明确允许其他登录用户查看、预览和下载;所有 `/api` 路由已有统一认证。 | | CR-10 | 低 | 防御性建议 | resolved | 删除弱类型 `mapToBSON`,改用显式 `bson.M`。 | | CR-11 | 低 | 文档建议 | resolved | 在 PowerFlow 持久化模型中明确本地 wall-clock 与 UTC instant 的语义。 | ## 3. 关键修复说明 ### 3.1 FileRequest 协调与 EMS 长轮询 - 新增 `data-download:request:{DocumentID}` 请求租约,RequestID 使用唯一 lease token。 - 租约每 40 秒续期,TTL 为 2 分钟;续租失败后提交校验会拒绝继续发布。 - Mutable 等待者携带 `AwaitRequestID`,按 15、30、60 秒退避重新入队;等待期间 item 保持 `pending`,不占用 worker。 - 同轮 Mutable 请求完成后,等待者只复用对应 RequestID 的结果;之后创建的新任务仍会刷新 Mutable 文档。 - Dynamic/UpdateLog 等待前一轮完成后重新竞争租约,不复用上一轮结果。 - 上游 EMS 轮询和文件下载不再持有 content 锁;content 锁只在上传及元数据切换阶段持有。 - 管理员删除文档时同时竞争 request lease,活跃请求期间禁止物理删除。 这解决了 CR-02,并落实了设计文档 3.2、8.2、9.1、9.2 的主要行为。普通 content/Renderer 锁的完整 fencing/CAS 仍由 DD-001、DD-007 跟踪。 ### 3.2 规划幂等 `InsertDataDownloadItems` 已由 `InsertMany` 改为无序 BulkWrite upsert。重复规划会取得已存在 item 的 `_id`,不会因唯一索引冲突失败;重复提交稳定 Asynq TaskID 时也不会把 item 错误标记为失败。该修复同时覆盖 plan handler 和 `site_validation` 重规划路径。 ### 3.3 任务计数 除原报告指出的 `Empty` 未写入外,复核还发现两个遗漏: - 某种状态消失时,旧 `succeeded/failed` 值不会归零; - aggregate 将 `skipped` 视为成功,但 Recount 未计入 succeeded。 当前 Recount 会先清零计数、将 `success + skipped` 汇总为 succeeded,并从 TaskDocument 统计空文档数。 ### 3.4 流式下载和 Package 生命周期 - Package、二进制文档和 RenderArtifact 下载改为 `SendStream`。 - 流式读取期间持有并续租对应锁,响应关闭后释放。 - Package 下载、人工删除和定时清理使用同一个 Package 锁,避免流式下载期间删除对象。 - Package 清理不再重算为 `清理时间+30天`,而是固定使用 `ExpiresAt+30天`。 ZIP 仍完整构建在内存中,Renderer 首次生成仍产生完整 `[]byte`,因此 DD-010 保持 open。 ## 4. 被否决的原结论 ### CR-01 `BuildDataDownloadPackage` 的 binary 分支自行取得 content 锁,structured 分支则直接进入 `ReadRenderedDataDownloadDocument`;两者不会在同一调用路径对同一 key 二次加锁。原报告描述的是假设未来修改后的风险,不是当前缺陷。 ### CR-03 旧 PowerFlow 导出和前端转换均以时间轴为基准,并允许较短的并行数组以空值补齐。当前实现拒绝长于时间轴的数组、保留短数组中的“缺测值”语义,没有证据证明应强制全部等长。新增单元测试防止未来把兼容行为误改为报错。 ### CR-09 设计文档 12.7 明确规定:其他用户可以查看任务和文件、预览、下载及批量下载,但不能修改、取消、重试或删除。归档读取属于文件查看/下载,且 `/api` 已由统一认证中间件保护,因此不能增加 owner/admin 限制。 ## 5. REPO-006 更正说明 原报告建议把 REPO-006 更正为 `GetAlarmSnapshotData`,该建议不正确。 REPO-006 描述的是旧测试 `service/test/getSnapTest/getAlarmSnapshotTest.go` 仍调用不存在的 `jobs.GetAlarmSnapshot`;DataDownload 新代码调用存在的 `jobs.GetAlarmSnapshotData`。两项事实同时成立,问题台账无需更正。 ## 6. 验证结果 - `go test ./services ./controllers ./repositories/mongo ./repositories/pgsql ./repositories/minio ./task/queue/dataDownloadQueue ./cache/redisx ./database`:通过。 - 新增 PowerFlow 回归测试:短并行数组补空;越界 `run_status` 被拒绝。 - `pnpm type-check`:通过。 - `pnpm exec eslint src/service/dataDownload src/views/data-download`:通过。 - `git diff --check`:通过。 - `go test ./...`:仍被 REPO-001~007 的既有源码问题阻断;DataDownload 相关包未出现新增失败。 ## 7. 仍需继续处理的风险 - DD-001:普通 content/Renderer 锁尚未全部统一为带 fencing 的租约。 - DD-002、DD-007、DD-008:PostgreSQL、Mongo Document、RenderSlot/Artifact 仍没有完整崩溃一致性和发布 CAS。 - DD-009:二进制上传后 Mongo 切换失败仍可能产生孤儿对象。 - DD-010:ZIP 构建、Renderer 首次生成和上游二进制获取仍有内存放大。 - DD-015:归档内部条目读取仍缺少大小上限。 - DD-023:缺少 Redis/Asynq/MongoDB/PostgreSQL/MinIO 跨进程与故障注入测试。