微信推送的"省着用"设计

2026-10-15

约束

通过官方通道给微信发消息,有个硬约束:全天主动发送上限 10 条。超过就发不出去。

10 条什么概念?系统里跑着几十个定时任务:邮件分拣、考研监测、福利领取、账号监控……每个都想推一条,分分钟超标。

设计:三级分流

┌─ 紧急 ──→ 立刻推送
待推送事项 ──┤
└─ 非紧急 ─→ 入队 → 定时 digest 合并发送

紧急标准(今天/明天内必须处理,错过即实质损失): - 截止类提醒(报名、缴费、兑换码先到先得) - 审核不通过需补材料 - 账号异常

非紧急(重要但可以等):简报、周报、价格政策变化等。

紧急的直接调发送脚本立刻发;非紧急的写入队列文件,等 digest 任务整理。

队列:JSONL + 文件锁

队列就是个 JSONL 文件,每行一条:

{"ts": "2026-10-15T14:30:00", "source": "inbox-scan", "text": "内容", "sent": false}

写入时加文件锁(fcntl.flock),防止多个任务同时写坏文件。实现很简单,30 行 Python。

Digest:每小时整理一次

digest 任务每小时跑一次,触发条件(满足一条才发):

  • 队列中待发送 ≥ 3 条,或
  • 最早一条等待 ≥ 3 小时

整理步骤: 1. 配额检查:先数今天已发了几条,≥ 8 条就跳过(给紧急推送留 2 条余量) 2. 去重:内容相似的合并为一条 3. 排序:按重要性排 4. 压缩:200 字以内一条发完,实在放不下最多分 2 条

发送成功后,已发送条目移出队列、记入已发送日志;失败的不重试,留到下次。

配额:三层防线

超标是最不能接受的,做了三层防线:

  1. 发送脚本内置检查:每次发送前数今天的发送日志,≥ 10 条直接拒绝
  2. digest 预留余量:digest 在 8 条就停手,留 2 条给紧急推送
  3. 审计日志:每次发送记一行,方便事后对账

为什么不用消息队列中间件

想过用 Redis/RabbitMQ,但: - 就一个 JSONL 文件能解决的事,没必要引入服务 - 文件锁在单机场景够用了 - 少一个依赖,少一个故障点

复盘

这套机制跑下来,最大的体会是:约束越硬,设计越要简单。10 条的限制逼着我把"什么值得打扰用户"想清楚——紧急的定义、合并的规则、余量的预留,每个数字背后都是一次取舍。

给做类似系统的建议:先定配额,再定分级,最后才是实现。顺序反了,代码写得再漂亮也是错的。

← 返回文章列表