Files
junhong_cmp_fiber/openspec/changes/archive/2026-08-20-daily-audit-log-retention/design.md
2026-08-20 12:03:17 +08:00

69 lines
5.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.
## Context
现有归档已按日生成 `tb_log_archive_run`,但 Integration Log 仅在月初终结整月 revision物理删除任务也只接受完整自然月。`tb_log_archive_run` 已按来源和归档日保存对象键、manifest、哈希、统计数和 `cleanup_started_at` / `cleaned_at`,可作为按日留存的断点账本。审计调查的在线边界当前通过每个来源的最大已清理范围计算;若出现清理日期空洞会错误隐藏仍在线的数据。
## Goals / Non-Goals
**Goals:**
- 每天将昨天及更早连续积压的归档日推进到可恢复、可校验、已物理清理的状态。
- 在任一日期归档、终结、对象校验或删除失败时保留在线数据,并使后续运行可安全续跑。
- 保持归档对象和 manifest 不删除,保持现有配置开关作为物理删除总闸门。
- 让在线查询边界只反映连续完成的日期。
**Non-Goals:**
- 不降低卡观测、轮询、Gateway 或 Integration Log 的写入频率。
- 不直接对生产表执行 SQL 删除,不绕过归档验证清理历史数据。
- 不改变归档 JSONL 格式、对象存储提供商或调查 API 路由。
## Decisions
### 以“归档日对”为最小留存单元
日留存以同一 Asia/Shanghai 日期的 Audit 与 Integration 两条归档账本为一个逻辑单元。任务处理上限固定为昨天,先确保两类归档存在;随后为 Integration 生成最终 revision确认该日不存在 `pending` 记录,并复用现有 manifest、对象 metadata、哈希和在线计数复核。
只有两个来源均通过验证后,才开始删除该日在线数据,顺序为 Audit Resource、Audit Event、Integration Log。删除仍按既有 1000 行批次进行;每个来源独立落 `cleanup_started_at``cleaned_at`,从而在进程中断后依据剩余计数续跑。
不采用“定时归档完成即直接 DELETE”的方案对象上传成功不等于可恢复且 Integration Log 的创建日可能仍有待完成记录。
### 按日期从早到晚推进,不跨越失败日
任务枚举昨天及更早仍未完成的归档日,从最早日期开始。某日失败、缺少归档或存在 pending Integration Log 时停止,不处理更晚日期。这样在线数据的已归档边界永远是连续前缀,历史积压在补齐归档后会由同一任务自动追赶。
不采用并行或跳过失败日期的方案:虽然可更快释放部分容量,但会产生在线数据日期空洞;当前调查响应只表达单一 `archived_before` 边界,不能正确描述空洞。
### 将 Integration 最终版由月度改为逐日形成
保留每日普通归档任务作为预归档;日留存任务在准备删除某日数据时对该日期执行最终归档。最终归档仍要求该日没有 pending Integration Log否则不删除并等待下次运行。原月度最终复核和月度留存调度移除避免与日留存争夺同一账本和产生不同的清理范围。
不采用固定延迟天数用户要求昨天及更早数据在可恢复后尽快清理pending 校验是每日期间的实际安全门禁。
### 查询边界按连续清理前缀计算
留存边界查询不再取任意来源的 `MAX(range_end)`。它必须从归档账本确认连续已清理日期,且多来源时间线使用两来源共同完成的连续边界;遇到未清理日期时停止。这样部分删除、失败重试或历史补档都不会把仍在线的旧日期标记为已归档。
### 使用独立文件记录留存结果与失败
新增独立的 Lumberjack/Zap 留存日志配置,默认路径为 Worker 工作目录下的 `logs/audit-retention.log`。日留存和日归档只向该日志写入日期推进、成功数量与耗时,或带日期、来源、失败分类的安全错误摘要;运营者无需在高噪声 `app.log` 中筛选。
不把诊断详情写入 `tb_log_archive_run.error_summary`。账本仍只保存归档状态、对象引用和清理断点;归档或留存失败的具体错误以独立文件为准。保留日志轮转和压缩,避免长期错误积压占满 Worker 磁盘。
不采用为每个日期新建单独文件的方案:一个按日轮转的专用流已经能按日期字段筛选,并避免文件数量随积压日期增长。
## Risks / Trade-offs
- [某日大量 pending 长期不终结,阻塞后续日期清理] → 记录日期、数量和原因;人工修复业务状态后由日任务续跑,不删除未完成数据。
- [单日数百万记录清理超过任务超时] → 维持小批次和来源级断点,任务重试时基于剩余记录续跑;按实测调整任务超时,不增大单事务范围。
- [归档或删除期间进程重启] → 账本的运行租约和清理标记保证归档可重做、删除可继续,且每次删除前重新验证剩余范围。
- [历史日期未建归档账本] → 日任务在最早缺失日期停止;先通过受控补归档形成完整连续账本,再允许自动物理清理。
- [日清理后数据库文件空间不立即下降] → 删除仅回收可复用空间;由维护者根据 PostgreSQL 运行状态决定后续 VACUUM 策略,不在 Worker 内执行高风险表重写。
- [独立留存日志写满磁盘或轮转配置错误] → 使用已有 Lumberjack 轮转、压缩和目录初始化机制;上线前核对 `logs/audit-retention.log` 的生成和轮转。
## Migration Plan
1. 发布包含日归档最终版、日留存和连续边界计算的 Worker/API 二进制,保持物理清理开关关闭。
2. 维护者核对历史归档账本的连续性按日期补齐缺失归档并以只读演练确认对象、manifest 和在线计数。
3. 维护者在低峰期启用 `JUNHONG_WORKER_AUDIT_RETENTION_CLEANUP_ENABLED=true` 并重启调度 Worker观察 `/opt/junhong_cmp/worker/logs/audit-retention.log`、账本断点和表大小。
4. 出现异常时关闭开关并重启调度 Worker已删除数据通过已验证的对象存储归档恢复未删除日期保留在线数据。