文章目录
- 约束
- 设计:三级分流
- 队列:JSONL + 文件锁
- Digest:每小时整理一次
- 配额:三层防线
- 为什么不用消息队列中间件
- 总结
约束
通过官方通道给微信发消息,有个硬约束:全天主动发送上限 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 小时
整理步骤:
- 配额检查:先数今天已发了几条,≥ 8 条就跳过(给紧急推送留 2 条余量)
- 去重:内容相似的合并为一条
- 排序:按重要性排
- 压缩:200 字以内一条发完,实在放不下最多分 2 条
发送成功后,已发送条目移出队列、记入已发送日志;失败的不重试,留到下次。
配额:三层防线
超标是最不能接受的,做了三层防线:
- 发送脚本内置检查:每次发送前数今天的发送日志,≥ 10 条直接拒绝
- digest 预留余量:digest 在 8 条就停手,留 2 条给紧急推送
- 审计日志:每次发送记一行,方便事后对账
为什么不用消息队列中间件
想过用 Redis/RabbitMQ,但:
- 就一个 JSONL 文件能解决的事,没必要引入服务
- 文件锁在单机场景够用了
- 少一个依赖,少一个故障点
总结
这套机制跑下来,最大的体会是:约束越硬,设计越要简单。10 条的限制逼着我把"什么值得打扰用户"想清楚——紧急的定义、合并的规则、余量的预留,每个数字背后都是一次取舍。
给做类似系统的建议:先定配额,再定分级,最后才是实现。顺序反了,代码写得再漂亮也是错的。
以上,全文完。
如果这篇文章对你有帮助,欢迎点赞收藏,也欢迎在评论区交流你的做法。
欢迎关注我的 CSDN 博客:https://blog.csdn.net/2301_80281820