姚章浩
|
3e4020c327
|
fix(drill): 支持空目标并在探针写入前落盘恢复证据
build / build (push) Successful in 1m21s
|
2026-10-31 02:56:44 +08:00 |
|
姚章浩
|
e0768f2caa
|
fix(library): 写集合台账与跨范围冲突预检
build / build (push) Successful in 1m34s
失败恢复会在写完之后按"目标租户里没人引用"清理资源行,于是历史孤儿、同租户其它
知识库暂未绑定的资源、被共享的资源都可能被删掉;而预备份里没有这些行,删了不可
恢复,随后整实例指纹才发现不一致,只能停在 rollback_failed。恢复校验依赖的整实例
证据又只存在内存里,worker 重启后只按快照 id 恢复,等于静默跳过比对。
改法:写第一笔之前把"本次明确写集合 + 写前存在状态 + 预备份时刻整实例内容证据"
算出来并按内容寻址落盘(文件名与治理库里的引用都是 sha256),摘要登记在预备份
版本证据里;恢复只删"写前不存在 ∧ 由本次写入 ∧ 不在恢复内容里"的精确 ID,并对
资源额外要求仍无绑定/正文引用;缺记录、记录被改、绑定对不上都直接失败、维护保持。
resources 的 upsert 补租户限定,跨范围同 ID 在写入之前就被预检拒绝。
整实例指纹从"身份集合"改成"逐行内容摘要",别的知识库同 ID 行被覆盖写坏也会暴露。
本地验证(已跑):
- make verify 15 项全 success(identity 因本地档案 skipped)
- go test ./internal/releaseadapter/v071/ -run Isolated(真实 PG + 真实 ES +
真实 MinIO 对象存储,写失败按定位符注入):目标非空/同租户其它知识库/共享资源/
历史孤儿/跨租户数据在失败恢复后逐行字节不变、本次残留 0;缺写集合拒绝恢复;
跨范围 ID 冲突在写入前拒绝;wiki 阶段半写回滚干净
- SIGKILL 子进程后按盘上写集合接管恢复,目标原有数据逐行不变
- go test ./internal/libraryrelease/:写集合先于第一笔、规划失败/登记失败都不写目标、
接管不重新规划
|
2026-10-29 23:55:13 +08:00 |
|
姚章浩
|
c27a0c14cc
|
fix(library): 基线契约读目标真实 schema/模型,演练标内容风险
build / build (push) Successful in 1m22s
真实演练暴露两个只有跑起来才看得见的问题:
1. 归档要求完整兼容性契约(v0.7.1 / schema 74 / elasticsearch_v8 / 1024 维 /
映射摘要),而基线装配只填了 embedding 与映射,捕获被
"unsupported snapshot compatibility contract" 拒绝。
现在 schema 版本读目标库 schema_migrations(dirty 或版本不符直接拒),
embedding 优先读目标库模型绑定(本机目标 models 表为空、引用悬空,
此时回落部署声明并说清来源),版本/引擎用受支持栈常量,映射取目标当前值。
2. 演练在"还没写目标内容"时就允许 restore_blocked=false 的窗口以 blocked 收尾,
写出 content_risk=false + restore_blocked=true 的非法 journal(恢复器拒绝加载,
目标停在停机态)。现在写 canary 时先 MarkContentRisk,allowRestore 按
"没碰内容 ⇒ 安全恢复;碰过 ⇒ 必须恢复并校验通过"。
另外给演练工具加 -recover:只把非终态窗口按原运行状态恢复,用于演练失败后
把目标救回来(不改治理记录)。
验证:库内模拟真实目标不可得,契约分支用真实 kgseal 演练覆盖:
snapshot 5cb945e6… 捕获 143ms → 基线一致 → canary 后校验如预期失败
(knowledges 1 行摘要不一致)→ 恢复后校验通过 → 窗口 succeeded、服务与入口恢复。
|
2026-10-29 19:41:12 +08:00 |
|
姚章浩
|
a42b101a7b
|
fix(library): 基线崩溃续作与维护原状态保留
build / build (push) Successful in 1m25s
父审发现三处会让目标卡死或状态对不上实际入口,逐条修:
1. 登记成功但没来得及收尾:崩溃重入会撞上"已有生效版本"直接失败,
目标留在维护里、占用也不释放。现在按「本作业+同一快照」识别为自己的
版本,只做收尾(恢复服务/开入口/释放两把占用),不重新捕获、不重写;
别人的版本仍然拒绝。捕获完成但登记失败则明确失败并写"未对目标写入"。
2. 重入覆盖原运行状态:崩溃时服务已被停住,再读一次只会读到 stopped,
写回去会让恢复阶段永远不启动写入者。AcquireInstance/LibraryMaintenance
在 owner 相同的重入时保留已持久化原状态;新作业接管已释放窗口用自己的观察。
真实 PostgreSQL 集成用例覆盖(先红后绿)。
3. 版本登记移进维护窗口:捕获/校验/登记要么一起成立、要么目标原样恢复;
记录失败时窗口已开放,治理状态同步释放,不再"显示维护中、实际已开"。
索引映射读不到时拒绝登记,不再用空摘要写证据。
顺带:
- 基线窗口统一收尾抽成 settleBaselineWindow,四种结局各有测试(成功/健康失败/
held 保持维护/已恢复则释放),并用真实 DB 用例证明 baseline 与 sync/restore
共用写互斥、幂等重试不产生第二个作业。
- 新增 cmd/librarydrill:维护隔离 → 整库预备份 → 一致性校验 → canary 漂移检测
→ 按预备份恢复 → 逐类复核 → 按原状态恢复服务。用与 worker 相同的 LIBRARY_*
配置,绝不触碰封存源。
- 目标/预备份/维护栈装配收成 internal/librarystack 一份(worker 与演练共用)。
验证:go build/vet/test 全过;TEST_DATABASE_URL 指向临时 PostgreSQL 跑
TestMaintenanceReentryKeepsOriginalServiceState(修复前失败:got app=stopped)
与 TestLibraryWriteMutexCoversBaselineJobs;本地门禁 15/15。
|
2026-10-29 19:08:58 +08:00 |
|