5.6 KiB
Context
见 proposal.md。当前 PollingCarddataHandler 与 PollingCardStatusHandler 在调用 Gateway 前创建 pending Integration Log,成功后再终结该记录;Integration Log 创建还会创建统一审计关联。因此一次无变化成功轮询至少造成审计事件、审计资源、Integration Log 创建和终结等多次 PostgreSQL 写入。生产轮询并发配置的数值远高于单机磁盘可承受范围,现有按任务类型的 Redis 信号量不能限制不同任务类型的合计压力。AuditRetentionCleanupEnabled=false 仅关闭物理删除,不阻止归档和留存扫描。
Goals / Non-Goals
Goals:
- 让无业务变化的成功轮询不产生 PostgreSQL 可调查记录。
- 保留支付、审批、入站回调和失败/未知外部调用的可靠持久化语义。
- 用跨 Worker 的总量与分类限流阻止轮询积压同时执行。
- 让归档和留存默认不参与日常生产负载,并能低峰限量推进。
Non-Goals:
- 不把支付、回调或审批的可靠幂等状态迁移到 Redis。
- 不删除历史审计或 Integration Log,不修改表结构或既有迁移。
- 不实现复杂自适应限流;先使用可验证的固定安全上限。
- 不改变轮询产生业务状态变化时的领域规则、Outbox 语义或渠道调用协议。
Decisions
1. 轮询完成后按结果决定是否记录
轮询路径先在内存中生成稳定的关联标识并调用渠道,再应用观测结果。只有失败、无效/未知响应或观测应用产生业务变化时,才持久化一个终态的轮询外部交互记录;成功且无变化直接进入下一次调度。
审计 Writer 只在观测业务变化或失败路径被调用。轮询专用的终态记录路径不得复用“调用前先写 pending”的通用可靠调用路径,以免重新引入无变化成功的两次写入和审计关联。
备选方案是在写入后异步删除无变化日志;它仍消耗 WAL 和索引 I/O,不能解决问题,故不采用。
2. Redis 仅承担协调与聚合
继续使用 Redis 保存轮询并发计数、短期去重和可选成功计数。原子获取脚本同时获取“全部轮询”令牌与“任务类型”令牌;任一令牌不足时不调用 Gateway,按现有重入队流程延后。释放和 TTL 修复必须同时覆盖两个计数,避免重启或 Worker 异常后令牌永久泄漏。
Redis 丢失后只会丢失短期协调或统计,轮询可以保守重试;可靠业务状态、支付/回调幂等和外部恢复继续在 PostgreSQL 中维持。
备选方案是让 Redis 保存所有 Integration Log 或回调幂等状态;Redis 不是权威持久化存储,故不采用。
3. 采用固定且受校验的并发预算
为全部轮询设置一个 Worker 配置总上限,并为每个任务类型保留现有动态上限。动态上限和总上限都必须校验为有限正整数;代码层硬上限防止生产误设为数千或数万。初始生产值由维护者在低峰期设置为保守值,并根据数据库 I/O、队列积压和渠道延迟逐项增加。
备选方案是只依赖 Asynq Worker Concurrency;它不能区分轮询和其他任务,也不能限制多实例或不同任务类型合计压力,故不采用。
4. 归档与留存采用默认关闭的总开关和单日预算
新增 Worker 配置总开关,默认关闭。关闭时不注册定时调度;处理器仍以安全 no-op 方式接住已入队任务,避免旧任务重试或扫描。开启时,各归档/留存执行只处理一个已结束的上海自然日;留存服务用“下一待处理日”替换跨历史日期循环。物理清理开关继续只决定是否删除,不改变新的任务总开关。
备选方案是只降低任务并发;现有跨历史日期循环单任务即可长时间占用数据库,故不采用。
5. 以可操作指标验证降载
轮询处理记录结构化计数:无变化跳过持久化、状态变化持久化、失败持久化、因总量/分类令牌延后。归档任务记录开关状态、处理日期和耗时。维护者据此结合 PostgreSQL I/O wait、活跃会话与 Asynq 队列深度决定是否提高预算。
Risks / Trade-offs
- [正常轮询不再可逐次调查] → 调查接口明确只展示变化、失败和人工事实;运行次数依赖聚合指标和应用日志。
- [失败后才建立轮询外部交互记录] → 使用同一内存关联标识写入终态失败记录,保留资源、场景、请求关联和恢复摘要。
- [Redis 令牌异常泄漏或丢失] → 原子双令牌脚本配合 TTL;丢失时按保守重试处理,不承担权威状态。
- [过低限流造成队列延迟] → 先保护数据库;监控积压、I/O 和渠道延迟后逐项提高,不允许绕过代码硬上限。
- [关闭归档导致历史在线数据继续增长] → 低峰期按单日预算受控推进,不能通过重新开启无界补偿来解决。
Migration Plan
- 维护者先使用现有轮询并发控制将所有任务类型降至保守值,并保持归档/留存 Worker 停止,记录 PostgreSQL 基线。
- 发布新配置与代码时,新归档/留存总开关保持关闭,轮询总并发使用保守值。
- 验证无变化轮询不新增三张日志表记录,失败和状态变化仍可调查,支付/回调幂等行为不变。
- 观察稳定窗口内 I/O wait、WAL 等待、队列积压和渠道延迟;每次只调整一类轮询预算。
- 低峰期手动开启归档/留存总开关,以单日预算推进;异常时关闭开关并停止相关 Worker。
回滚时恢复上一版二进制和原有配置;已跳过的正常无变化日志不补写,已积压的归档日期仍按受控任务处理。