fix(sync): reconciler 清扫环补 ad——错过的 ad.* 推送恢复自愈通道
SWEEP_ENTITY_TYPES 追加 'ad':生产对账循环阶段一逐类拉 cn reconcile 清单时纳入广告当前态(清单恒全量、确定性排序),重放走既有 content-batches 幂等管道。此前 ad 只有 cn 端点而无调用方——ad.* outbox 事件「投后即失」时 ads_ov 无自愈路径(digest 是相册维度计数,覆盖不了 无相册归属的广告;含 enabled=false 下线与硬删墓碑后的终态收敛)。 sweep() 对各类型均一处理(无 per-type 簿记),'ad' 与 'asset' 同构接入; 文件头/Stats 注释同步(四类→五类)。 测试:reconcile.e2e ⑤ 追加 runOnce 生产环断言——sweptEvents=5 (album+photo×2+ad×2)、replayApplied=2(仅 ad 新 eventId)、 ads_ov 两行投影就位(全局 albumIds NULL/定向数组)、digest 稳态不受 影响。sync 全量 e2e 4 suites/28 tests、api ads 16/16、typecheck/lint 净。 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,9 @@
|
||||
// ⑤ (ads-carousel Task 8)cn 对账 'ad' 清扫:直种两行 ads(全局+定向)→
|
||||
// 签名 POST /internal/sync/reconcile {entityType:'ad'} → 2 条当前态
|
||||
// wire 事件(albumId 恒空串、载荷=全量快照、确定性 recon:ad:{id}:{v}
|
||||
// 合成 eventId,sortOrder 升序确定性排序)。
|
||||
// 合成 eventId,sortOrder 升序确定性排序);随后 runOnce 走生产清扫环
|
||||
// (SWEEP_ENTITY_TYPES 含 'ad')→ ads_ov 投影就位——错过的 ad.* 推送
|
||||
// 由此获得 digest 之外的自愈通道(digest 相册维度覆盖不了 ads)。
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { type NestExpressApplication } from '@nestjs/platform-express';
|
||||
import request from 'supertest';
|
||||
@@ -467,5 +469,34 @@ describe('sync reconcile + digest healing (e2e)', () => {
|
||||
entityVersion: 1,
|
||||
},
|
||||
});
|
||||
|
||||
// 生产清扫环贯通:runOnce 阶段一逐类拉清单(含 'ad')→ 签名推送 ov →
|
||||
// ads_ov 投影就位(模拟「ad.* outbox 事件全部投后即失」——清扫当前态
|
||||
// 快照重放即补齐,ov 侧 eventId 幂等 + 版本单调承担判重)。
|
||||
const stats = await reconciler.runOnce();
|
||||
// album v5 + photo×2 v2 + ad×2(category ③ 已删、asset 无行)。
|
||||
expect(stats.sweptEvents).toBe(5);
|
||||
// 仅 ad 两条为新合成 eventId(album/photo 的 recon 事件 ①-④ 已入账判重)。
|
||||
expect(stats.replayApplied).toBe(2);
|
||||
// digest 相册维度不受 ads 影响:稳态无 bootstrap。
|
||||
expect(stats.mismatchedAlbums).toEqual([]);
|
||||
expect(
|
||||
await prismaOv.ads_ov.findUnique({ where: { adId: 'recon-ad-global' } }),
|
||||
).toMatchObject({
|
||||
adId: 'recon-ad-global',
|
||||
imageObjectKey: 'photo-live/dev/ads/recon-ad-global/v1.jpg',
|
||||
linkUrl: 'https://sponsor.example/global',
|
||||
sortOrder: 10,
|
||||
albumIds: null,
|
||||
entityVersion: 1,
|
||||
});
|
||||
expect(
|
||||
await prismaOv.ads_ov.findUnique({ where: { adId: 'recon-ad-targeted' } }),
|
||||
).toMatchObject({
|
||||
adId: 'recon-ad-targeted',
|
||||
sortOrder: 20,
|
||||
albumIds: [albumId],
|
||||
entityVersion: 1,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user