Files
sundynix-agentix/sundynix-gateway/internal/store/leader_test.go
T
Blizzard f16f63284f feat(cluster): gateway 后台定时器加 leader 锁——多副本安全(B5)
此前两个 gateway 定时器(订阅推进/掉单补偿)每实例各扫一遍:多副本下重复查库,
且对微信查单调用量随副本线性放大(微信有频控,先被限流的是自己)。

store.TryRunExclusive:用 PG advisory try-lock 做集群级单实例执行(leader 选举)——每轮
tick 非阻塞抢锁,抢到才跑、跑完释放;抢不到说明别的实例是 leader、本轮跳过。自愈:锁随
持有连接释放,leader 挂了下一轮别的实例自然抢到接管,无需显式故障转移。订阅/补偿用不同
锁键(可由不同实例分别 lead)。非 PG(sqlite 测试)/无 DB → 退回本地直接跑(单实例安全)。

两个定时器的 tick 各包一层 TryRunExclusive。至此 gateway 可安全多副本(SSE 走共享 Redis
流无需粘性、状态全外置、JWT 无状态,剩数据层 HA 属 C 层 ops)。带 fallback 单测。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 16:21:31 +08:00

25 lines
775 B
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package store
import (
"context"
"testing"
)
// 非 PGsqlite 测试库无 pg_try_advisory_lock):选主不可用 → 退回本地直接跑(单实例/开发态不能因此不跑)。
func TestTryRunExclusive_FallbackRunsOnNonPG(t *testing.T) {
p := newTestStore(t)
ran := false
if got := p.TryRunExclusive(context.Background(), 987654, func() { ran = true }); !got || !ran {
t.Fatalf("sqlite 无 advisory 锁应退回本地跑:got=%v ran=%v", got, ran)
}
}
// 无 DB(降级模式):一样本地直接跑。
func TestTryRunExclusive_NilDB(t *testing.T) {
p := &Postgres{}
ran := false
if got := p.TryRunExclusive(context.Background(), 987654, func() { ran = true }); !got || !ran {
t.Fatalf("无 DB 应本地跑:got=%v ran=%v", got, ran)
}
}