大促当天有 3000 多条通知没发出去,日志里查不到任何失败记录。线程池配置是 core 4 max 8 queue 0,拒绝策略用的是 DiscardPolicy。第一次遇到会往复杂处想,其实漏掉的多是个小前提。
ThreadPoolExecutor(4, 8, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(2000),
new ThreadPoolExecutor.CallerRunsPolicy());
队列长度设成 0,核心线程占满后新任务直接被拒绝。DiscardPolicy 丢弃时不抛异常也不打日志,调用方以为提交成功。异步链路没有落库,事后无法补偿。这一点先确认清楚,后面就不用反复试。
「异步发送无重试」这类改动最怕改一半,回滚脚本先准备好,再动生产。新版本先放一台机器上跑一天再全量,问题一般在这段时间暴露。
备份不是备了就行,恢复一次才算数,很多备份文件打开才发现是空的。
具体做法是,拒绝策略改成 CallerRuns 或抛异常 让调用方感知;发送任务先落库 状态 pending 再异步消费;消费失败按指数退避重试 最多三次;对 pending 超过十分钟的记录告警。
改完照着核一遍,压测把线程池打满后,发送失败能在日志和表里查到,补偿任务把 pending 记录清空,没有静默丢失。
