fix(notify): 汇总模式按消息计量限流,批次大小不再被每轮请求预算掐死

令牌桶的额度此前被同时当成两个量纲用:对实时模式它是「发几条消息」,
对汇总模式却被直接当成「一批装几条漏洞」传给 ClaimDigestBatch。

notifyMaxSendsPerChannelPerTick(=5)是由租约时长倒推的 HTTP 请求预算,
而一个汇总批次只发一次请求,两者本不该相乘。稳态下更糟:rate_per_min=20
的渠道在 3 秒的 tick 里只补得到 1 个令牌,于是每条汇总消息只装 1 个漏洞,
头部还写着「近 30 分钟新增 1 个漏洞」——digest 退化成带汇总文案的实时推送,
MaxDigestBatchSize(500) 永不可达。

改为统一按**消息条数**计量:一批漏洞合成一条消息、消耗一个令牌,
rate_per_min 对 digest 依然生效(每分钟最多这么多条汇总消息),
而批次大小只受 MaxDigestBatchSize 这个内存上界约束。

ClaimDigestBatch 原先的注释声称「单批同时受限流额度与内存上界约束」,
那正是本问题的来源——限流额度本不该充当批次大小。注释一并改掉,
免得下次又按「rate_per_min 对 digest 不生效」把它改回去。

顺带让 takeTokens 接受 want 上限:原先整桶抽空后才由调用方截断,
多出来的令牌(飞书默认 100/min 时是 95 个)直接丢弃,渠道这一轮
没有待发投递时也照扣,注释声称的突发容量在任何情况下都做不到。

决策收在 digestTickPlan 里由新增用例直接钉住。现有端到端用例都手动给
stepDigest 传一个够大的 limit,绕过了 step 里的额度计算,所以覆盖不到这里。
This commit is contained in:
Autumn-27 committed 2026-10-01 06:43:29 -04:00
1 parent f2f35ebc2e
commit 93c1d39df3
3 files changed
+123 -26

No files matched your search

+9 -3
View File
@@ -171,9 +171,15 @@ func (d *DB) ClaimDigestBatch(ctx context.Context, channelID int64, limit int, l
if limit <= 0 {
return nil, nil
}
// 单批同时受两个上界约束:调用方的限流额度(本轮还能发几条)与内存上界
// MaxDigestBatchSize。此前只用了后者,于是 digest 渠道的 rate_per_min
// 完全不生效——令牌被 takeTokens 扣掉却没人用,等于白扣。
// limit 是**内存上界**,调用方传 MaxDigestBatchSize;这里再夹一道,
// 防止调用方传进一个更大的值。
//
// 刻意不接受「限流额度」充当批次大小:限流的单位是消息条数——一个批次只发
// 一条消息、消耗一个令牌,由 server 层的 takeTokens 扣除——与「一批装几条
// 漏洞」是两个不同的量纲。曾经为了让 rate_per_min 对 digest 生效而把每轮
// 请求预算传进来当批次大小,结果 rate=20/min 的渠道每批只装 1 条漏洞,
// digest 退化成带汇总文案的实时推送。要改限流请改 takeTokens 的 want,
// 不要动这里。
if limit > MaxDigestBatchSize {
limit = MaxDigestBatchSize
}