Commit Graph

52 Commits

Author SHA1 Message Date
9da61452a9 chore(retry): 新增 SMS 限流重试的库侧脚本(MA:0038 映射 + 普通类阶梯)
resources/sql 下两份手工执行迁移脚本(供 DBA 在目标库运行,均幂等):
- provider-error-code-mapping/telecom_sms_MA0038_retryable.sql:
  给 push_provider_error_code_mapping 配 (telecom,sms,MA:0038 ->
  unified_error_code=RATE_LIMIT, should_retry=1)。与 TelecomSmsSender
  的 status=6 改动(c892f71)缺一不可——MA:0038 才能进重试链并被识别为限流类。
- sms_retry_strategy_ladder.sql:
  普通类 sms 失败重试阶梯 retry_intervals='60,120,300,600'、max_retry_count=6
  (TD-3 决策),取代旧 quickfix 的 60s 平铺;限流类由代码 120s/12h 保证,不读此表。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 23:11:00 +08:00
c892f71711 fix(sms): 电信回执 status=6(MA:0038 限流)纳入失败映射,不再静默丢弃
电信下行回执查询对"短期频繁发送"类返回 status=6 / stat=MA:0038,
原代码仅处理 status=5,status=6 无分支被直接丢弃 —— 该类短信永远
进不了失败/重试链路。改为 status==5 || status==6 一并走 buildFailureResult,
由 push_provider_error_code_mapping.should_retry 决定是否重试。

这是限流类无限重试治本(批次1-3)在回执侧的触发点,与库内
MA:0038 -> RATE_LIMIT 映射种子(TD-2)缺一不可。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 15:40:43 +08:00
8231b1e0e1 fix(retry): 修复批量入队 NPE(next_retry_time 取错数据源)
根因:fallbackToDatabaseDirectly / rebuildRetryQueueOnStartup 批量入队时,
取的是 push_message_record.next_retry_time(只在内存设置、不保证落库,常为 null),
而调度权威其实是 push_message_retry_queue.next_retry_time(已落库、查询已保证非空)。
定时任务回落 DB 时拿到 null 的 message,addToRetryQueue 调 atZone 即 NPE,
整个 SMS 重试定时任务被带崩。

治本:新增 fillNextRetryTimeFromQueue,用队列记录的权威 nextRetryTime 回填
message 再入队,两条批量路径各调用一次 —— 不丢消息、照常重试。
兜底:addToRetryQueue 对 nextRetryTime==null 打 warn 并跳过单条,
保证任何坏数据都不会再把整批/整个定时任务带崩。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 19:33:00 +08:00
f076dcd9b2 feat(retry): 批次3 限流类自动重试守卫豁免(让无限重试在生产真正生效)
接 16974d0(I3)。Task8 核实:限流类自动重发途经 MsgPushGuardChain 的
Quota/RateLimitChecker,per-receiver 日限远小于 ~360 次/12h,会被守卫置
rate_limited/quota_exceeded 终态 → 队列记录被删 → 无限重试静默失效。
批次1/2/I3 修对了重试编排,但不豁免守卫则功能在生产仍发不出去。

方案 A+B(用户选:完全豁免 AUTO_RETRY):
- A:checkAll 加 RetrySourceEnum 参,AUTO_RETRY 跳过 quota+ratelimit
  (blacklist 仍执行);processSendMsg 透传。重发节奏由 120s 间隔 + 12h
  兜底天然封顶,无需配额墙再约束。
- B:applySendResult 加 retrySource 参,仅首发(null)累加配额/频率计数;
  重发(AUTO/MANUAL)是同一条消息再投,不重复扣额。
- MANUAL_RETRY 仍受守卫检查(只豁免 AUTO)。

checkAll 全仓仅 1 调用点;applySendResult 为 impl 内部方法、2 处 this 调用,
接口签名不变。Spring 编排+Redis 副作用无 H2 脚手架,靠编译+diff+人工冒烟
验证(spec §8):RetryDecisionLogicTest 仍 6/6 绿,全模块编译通过。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 17:39:12 +08:00
16974d04f9 fix(retry): 修复 I3 限流/普通共用 retryCount 跨污染
接 cbfee6b。retryCount 原被限流与普通失败共用累加,而终止判定按本次
errorCode 在 12h 兜底与次数上限间翻转:限流重试撑高 retryCount 后一旦
出现普通失败,会被 retryCount>=maxRetry 提前判死;反之普通累计接近上限
后转限流又借 12h 续命绕过次数上限。

最小治本(不动 DB):retryCount 语义收敛为普通失败次数,限流重试冻结
它(靠 firstFailTime+12h 兜底终止)。
- 新增 nextRetryCount(current, rateLimit):限流冻结、普通累加。
- applyRetryUpdate 改用 nextRetryCount;insert 路径首次限流 retryCount=0、
  普通=1。firstFailTime 维度本无污染(只设一次),不动。

测试:RetryDecisionLogicTest 新增 2 例锁回归,原 4 例不变,共 6/6 绿;
全模块编译通过。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 17:28:28 +08:00
cbfee6b156 fix(retry): 修复批次1+2 review 查出的两个 blocker(I1 撤唯一约束 / I2 SENDING 泄漏)
99c8bc3 多代理深度 code review,治本两个 blocker:

I1 软删除 × 唯一约束 → 静默丢消息(撤批次2):
- MessageRetryQueueDO 走 @TableLogic 逻辑删除,deleteByMessageIds 实为
  UPDATE deleted=1,物理行残留;批次2 的 uk_pmrq_message_id 只盖 message_id,
  与残留行冲突 → 同一 message_id 再入队抛 DuplicateKeyException → catch 再
  selectOne 仍 null(软删行不可见)→ concurrent==null 静默 return → 消息永久丢失。
- 撤回:删迁移 SQL、移除 DuplicateKeyException catch 与 import,回到纯
  selectOne→insert/update;applyRetryUpdate(含批次1 限流逻辑)保留为单点调用。

I2 SENDING 行泄漏 + 周期空转(最小治本):
- processSingleRetry 的 else 把"保留中间态"白名单误用在重认领路径;能被重认领
  说明 120s 租约已过期、20s 回执窗口早过,SENDING/PENDING 属卡住却被保留 →
  永不删除/推进、到不了 12h 兜底、周期空转。改前的无条件 delete 会自愈。
- 改回 else { delete }(重认领即清理);删死代码 isTerminalState / INTERMEDIATE_STATES;
  保留 finalizeRetryLease 的 SENDING→return(发完即时窗口保住行,批次1 修 R1 关键)。

测试:RetryDecisionLogicTest 删 isTerminalState 两例、清死 import,余 4 例全绿;
全模块重编译通过。设计见 docs/superpowers/specs/2026-06-19-sms-retry-blockers-fix-design.md。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 17:04:47 +08:00
99c8bc3636 feat(retry): SMS限流类无限重试治本(批次1核心 + 批次2唯一约束)
批次1 治本核心(MessageRetryQueueServiceImpl):
- 新增常量与纯函数 helper:isRateLimit / isRateLimitExhausted / isTerminalState,
  及 RetryDecisionLogicTest 纯JUnit5单测(6例)
- A1/A2 删除时机:sending 中间态不再误删,仅终态才删 —— 根治 firstFailTime/retryCount
  被重置的 R1 根因(回执回来命中既有记录而非走首次入队)
- B1/B2 限流分流:限流类(errorCode=RATE_LIMIT)按"首次失败起满12h"时间兜底、
  固定120s间隔;普通类维持次数上限与阶梯间隔,行为不变

批次2 唯一约束:
- 新增 push_message_retry_queue.message_id 唯一约束迁移SQL(uk_pmrq_message_id,含去重前置查)
- saveOrUpdateRetryMessage 抽 applyRetryUpdate + 捕获 DuplicateKeyException 退化更新(MySQL安全)

说明:批次3(守卫链对限流类重发的豁免)经核实为"功能真正生效的必要条件",
findings 见 docs/push模块/配额墙核实-findings-2026-06-19.md,留待下轮。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 16:04:34 +08:00
caozehui
c2bbdd865d 系统凭证调整 2026-05-13 09:47:54 +08:00
caozehui
e9f66ca0b2 微调 2026-05-12 16:02:11 +08:00
caozehui
8f86c563f0 微调 2026-05-12 11:22:26 +08:00
caozehui
db15799440 微调 2026-05-12 08:42:07 +08:00
caozehui
c4b56a727c 微调 2026-05-11 15:49:05 +08:00
caozehui
fe26aa8670 微调 2026-05-11 13:57:02 +08:00
caozehui
9343799290 引入阿里云邮件推送 2026-05-11 10:57:40 +08:00
caozehui
9be824777b 开放 生成系统凭证 接口 2026-04 2026-04-20 19:55:21 +08:00
caozehui
8c2f5a0e17 微调 2026-04-20 11:15:16 +08:00
caozehui
c147ef602f 删除消息重试队列delete字段 2026-04-20 11:13:21 +08:00
caozehui
cb9a75084f 处理Redis认领后,数据库状态还未更新时,触发补招,导致重复补招同一个条记录问题 2026-04-20 08:46:27 +08:00
caozehui
47c00e2bd4 服务提供商启用\禁用逻辑调整,确保只有一个渠道只有一个服务提供商 2026-04-17 16:11:00 +08:00
caozehui
d44f6423e0 微调 2026-04-09 18:31:55 +08:00
caozehui
fc6fc9642b 重试逻辑调整 2026-04-09 13:39:10 +08:00
caozehui
0a8627b440 第三方调用异常与事务边界、消息重试队列Redis与数据定时同步任务、重试次数闭环不稳定 2026-03 2026-04-07 08:40:51 +08:00
1bf5436f0c 1、微调 2026-04-01 20:33:59 +08:00
8c43ec408d 1、id自增调整为雪花模式 2026-03-31 20:57:52 +08:00
e78565ea5a 1、结构化调整; 2026-03-31 19:58:48 +08:00
ebdbdbeb41 1、结构调整
2、抽象工厂优化
2026-03-31 19:35:21 +08:00
caozehui
87757b352c 配额 2026-03-30 13:58:03 +08:00
caozehui
be7c1b7b26 系统配额、redis缓存各个系统&渠道发送消息的数量 2026-03-23 15:39:10 +08:00
caozehui
6934e19030 微调 2026-03-16 11:17:11 +08:00
caozehui
5feae9e403 发送频率限制数据访问层、服务层 2026-03-16 10:40:42 +08:00
caozehui
2fa61b350c 黑名单数据访问层、服务层 2026-03-13 08:49:45 +08:00
caozehui
e281226069 完善消息错误信息、编写消息重试队列 2026-03-12 09:13:43 +08:00
caozehui
6a0bb5f23e 修改消息的状态 2026-03-10 10:46:44 +08:00
caozehui
478f8a4c3d 电信获取下行信息完善、补充消息重试队列、消息重试任务 2026-03-10 10:35:42 +08:00
caozehui
8806ba7afa 获取下行状态 2026-03-06 08:42:19 +08:00
caozehui
b048ecfc53 微调 2026-03-04 20:37:48 +08:00
caozehui
cfa3f1759c Merge remote-tracking branch 'origin/main' 2026-03-04 19:30:44 +08:00
01df90000b 添加配置 2026-03-04 19:29:53 +08:00
caozehui
464b37f641 Merge branch 'dev'
# Conflicts:
#	msgpush-module-push/msgpush-module-push-server/src/main/resources/application.yaml
2026-03-04 19:21:57 +08:00
caozehui
9c5d4b6d11 微调 2026-03-04 19:16:53 +08:00
32c0af9f1d 添加配置 2026-03-04 19:11:26 +08:00
1fd0cb1f45 微调 2026-03-04 13:18:49 +08:00
495854243f 端口调整 2026-03-04 09:19:14 +08:00
caozehui
ceb065ec97 微调 2026-03-04 09:13:23 +08:00
caozehui
10febe21f9 微调 2026-03-03 10:39:41 +08:00
caozehui
8b4a7967cc 结构调整 2026-03-03 10:33:03 +08:00
caozehui
c7f3687bf8 短信推送demo 2026-02-26 15:45:19 +08:00
caozehui
fac4a39214 微调 2026-02-11 16:17:13 +08:00
caozehui
1219b30f43 微调 2026-02-10 15:27:28 +08:00
3f65a55c15 清除多租户功能 2026-02-04 15:41:21 +08:00