把「发送成功」当「送达」?我排查 IM 长消息被静默吞掉的完整过程
做无人值守内容矩阵时,我遇到一个非常隐蔽的坑:Agent 定时推送 IM 消息,日志里 rc=0 全是绿灯,可实际一条都没送达,服务端静默吞掉了。这篇文章记录完整排查过程,给同样跑自动化推送的人一个参考。
现象
某天早上看后台,日志一片绿:
2026-10-18 03:12:44 [INFO] push msg #1201 -> rc=0
2026-10-18 03:12:44 [INFO] push msg #1202 -> rc=0
2026-10-18 03:12:44 [INFO] push msg #1203 -> rc=0
rc=0 通常代表成功,但客户反馈一条都没收到。这是典型的「假成功」。
排查路径
1. 先排除网络层
检查了出网、连接池、重试次数,全部正常,排除网络抖动。
2. 对比「发送数」与「送达数」
这是关键一步。我把推送任务里记录的 sent_count 和 IM 服务端回执里的 delivered_count 拉出来对比:
# 伪代码示意
for task in tasks:
sent = task.sent_count # 我这边记的
delivered = task.delivered_count # 服务端回执
if sent != delivered:
logger.warning(f"task={task.id} sent={sent} delivered={delivered}")
一跑,发现 sent=3 delivered=0,问题锁定在服务端丢弃,而非网络。
3. 定位到「长消息被吞」
逐条对比后发现,被吞的全是超长消息(单条几万字)。IM 服务端对单条消息有长度上限,超限的直接静默丢弃,不返回错误码。
验证:把一条超长消息拆成 10 条短消息,全部送达。
解决方案
按长度拆包发送
MAX_LEN = 4000 # 服务端单条上限,按你对接的 IM 调整
def chunk_text(text: str, limit: int = MAX_LEN):
return [text[i:i+limit] for i in range(0, len(text), limit)]
for chunk in chunk_text(long_text):
push(chunk)
加「看门狗」对账
发完不是结束,起一个对账任务核对发送数与送达数,对不上就告警:
def watchdog():
for task in tasks:
if task.sent_count != task.delivered_count:
alert(f"静默丢失: task={task.id}")
教训
rc=0只代表「发出去了」,不代表「送达了」。自动化推送必须核对底层回执。- 长消息是静默丢弃的高发区,务必按长度拆包。
- 无人值守系统里,「静默」比「报错」更可怕——报错能触发告警,静默只能靠对账兜底。
这套「拆包 + 对账看门狗」已经跑进我的矩阵,从「半夜静默」变成「半夜被吵醒但至少知道」。希望对你有用。