| 123456789101112131415161718192021222324252627 |
- using Admin.NET.Plugin.AiDOP.MaterialWarehouse.InventoryPosting.Entity;
- namespace Admin.NET.Plugin.AiDOP.MaterialWarehouse.InventoryPosting.Idempotency;
- /// <summary>
- /// IQC 过账头幂等存储抽象。唯一性由 (tenant_id, domain_code, fbillno) 的 DB UNIQUE 保证;
- /// TryInsertAsync 依赖唯一约束原子占位——**不是** SELECT-不存在-INSERT(无并发窗口)。
- /// 生产实现走 SqlSugar + duplicate-key(1062) 捕获;测试实现走线程安全内存。
- /// </summary>
- public interface IIqcPostingStore
- {
- /// <summary>尝试插入过账头(PROCESSING)。UNIQUE 冲突 → Inserted=false 并尽量带出既有记录。</summary>
- Task<PostingInsertResult> TryInsertAsync(AdoIqcInventoryPosting posting);
- /// <summary>按幂等键读取既有过账头。</summary>
- Task<AdoIqcInventoryPosting> GetAsync(long tenantId, string domainCode, string fbillNo);
- /// <summary>业务提交成功/失败后回写过账状态(POSTED / FAILED)。</summary>
- Task UpdateStatusAsync(AdoIqcInventoryPosting posting, string status);
- /// <summary>
- /// 原子抢占 stale PROCESSING(Phase 7C):仅当 status=PROCESSING 且 update_time < <paramref name="staleBefore"/>
- /// 时把 update_time 刷新为 <paramref name="now"/> 并返回 true(心跳续租=抢占成功)。**单条件更新原子完成**,
- /// 不做 SELECT-then-UPDATE,杜绝竞态窗口——并发多路仅一路 rows=1。lease 未过期或已被他路抢占 → false。
- /// </summary>
- Task<bool> TryRecoverStaleAsync(long tenantId, string domainCode, string fbillNo, DateTime staleBefore, DateTime now);
- }
|