Documentation
¶
Overview ¶
Package invalidate 管理面变更的去抖定向失效:
脏标记(Mark 路径零锁零 DB——atomic CAS 合并 + 非阻塞唤醒,不阻塞任何 调用方;消除 压测实证的 33,705 goroutine reloadMu 串行雪崩)+ 定时窗口到点批量执行一次合并重载;后沿语义(执行完成后若又脏 立即再执行,不按固定间隔 throttle——不与长 reload 重叠)。
接线矩阵(定稿,reloadAll 实现):
- 用户 CRUD(含创建)/余额变更 → auth + 余额快照全量(新用户必须即刻在 快照——防 ≤10s 402 窗口,回归测试 tools/e2e)
- 模板(base_url/models/映射)→ sched 全量 + clients 失效(base_url 变更需按新地址重建 SDK 客户端)
- 账号 → sched 组级定向 InvalidateGroup(包含关系:full ⊇ 组级 ⊇ 无)
- 组倍率 / 用户-组专属倍率 → 余额倍率快照定向刷新(EffectiveMultiplier 陈旧 ≤10s 不可接受)
- key CRUD(多实例 key 缺口)→ auth 快照全量 Reload(v1 不做增量 定向——单实例 auth 增量 Upsert/Delete 语义不变,多实例需全量覆盖其余 实例的陈旧快照)
- 规则 CRUD → 规则表全量重载(重载清窗口计数,全实例同步执行语义)
- 本地 settings 变更(UpdateSetting)→ 去抖器 KindSettings → auth 快照 全量 Reload(gate 预算按新 N 重算;settings 快照本身由发布端同步刷新, 本 mark 只承担 scope 声明方重载);远端 NOTIFY settings → dispatcher 同步 ReloadSettings + scope 声明方(保持现状)
- 定价快照变更 → dispatcher 直连 svc.ReloadPricingCtx(低频同步路径, 不入本去抖器)
读端永不阻塞:重载在单 goroutine 串行执行;各实体快照原子替换由实体自身 保证(scheduler snapshotStore / Balances atomic.Pointer / Auth RWMutex 换 整体),本包只在变更侧去抖合并。
Index ¶
- Constants
- type AuthReloader
- type BalancesReloader
- type ClientsReloader
- type Config
- type Debouncer
- func (d *Debouncer) Accounts(gids []int64, keyChanged bool)
- func (d *Debouncer) Clients()
- func (d *Debouncer) Close(ctx context.Context) error
- func (d *Debouncer) Keys()
- func (d *Debouncer) ManagementKeys()
- func (d *Debouncer) Multipliers()
- func (d *Debouncer) Name() string
- func (d *Debouncer) Rules()
- func (d *Debouncer) Settings()
- func (d *Debouncer) Start(ctx context.Context) error
- func (d *Debouncer) Stats() any
- func (d *Debouncer) Templates()
- func (d *Debouncer) Users()
- type DebouncerStats
- type Kind
- type RulesReloader
- type SchedReloader
- type State
Constants ¶
const DefaultWindow = 200 * time.Millisecond
DefaultWindow 去抖窗口。生效延迟语义:管理面变更在 ≤200ms 窗口到点后执行 一次合并重载(总延迟 = 窗口 + 一次重载时长;定稿 ≤200ms 可 接受——新用户 402 窗口回归测试对"建用户 → <0.5s 请求 → 200"做硬断言)。
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AuthReloader ¶
AuthReloader 鉴权快照全量重载(proxy.Auth 实现)。
type BalancesReloader ¶
type BalancesReloader interface {
Reload(ctx context.Context) error
ReloadMultipliers(ctx context.Context) error
}
BalancesReloader 余额/倍率快照(billing.Balances 实现;billing 关闭时 nil, reloadAll 跳过余额路径)。
type ClientsReloader ¶
type ClientsReloader interface {
InvalidateAll()
}
ClientsReloader aiclient 工厂客户端失效(aiclient.Factory 实现)。
type Config ¶
type Config struct {
Window time.Duration // 去抖窗口(0 → DefaultWindow)
Sched SchedReloader // 必填
Clients ClientsReloader // 必填
Auth AuthReloader // 必填
Balances BalancesReloader // billing.enabled=false → nil
Rules RulesReloader // 可选(nil → rules 分支跳过)
Log *logx.Logger // 可空(nil = 不记日志)
}
Config 装配参数(main 接线)。
type Debouncer ¶
type Debouncer struct {
// contains filtered or unexported fields
}
Debouncer 去抖器(核心):
- Mark 路径(Users/Templates/Accounts/Multipliers):零锁零 DB——原子 CAS 合并脏状态 + 非阻塞 channel 唤醒;任何调用方(含 50k 并发 fill)不阻塞。
- 执行路径:单 goroutine 串行(Start 启动),窗口到点消费脏状态执行合并 重载;执行期间新变更 → 完成后立即再执行(后沿语义)。
同时满足 service.Invalidator 接口(main 装配传给 service.New)。
func (*Debouncer) Accounts ¶
Accounts 账号变更(创建/更新/删除/批量):sched 组级定向重载受影响组 (gids;与全量位同窗口时被包含跳过);keyChanged(身份类字段变更:模板 / 生效 origin / upstream_key)→ clients 失效(连接缓存键内含这些事实)。 gids 空且 keyChanged=false(纯配置类变更)→ 无任何快照受影响,直接 no-op(不入脏)。
func (*Debouncer) Clients ¶
func (d *Debouncer) Clients()
Clients 仅客户端工厂失效(aiclient.Factory.InvalidateAll):模板/账号 变更以外独立出现的 clients 失效(notify Dispatcher 独立映射; 服务端发布点恒与 Templates 或 Groups 并排,此处是防御性兜底)。
func (*Debouncer) Close ¶
Close 无操作:循环随 Start 的 ctx 取消退出(worker 契约:幂等、未 Start 也 安全)。停机不补最后 flush——DB 权威,残留变更随下次启动全量加载。
func (*Debouncer) Keys ¶
func (d *Debouncer) Keys()
Keys key CRUD(创建/轮换/删除/改额度 多实例 key 缺口):auth 快照全量 Reload(v1 不做增量定向——现状 auth 增量 Upsert/Delete 是单实例语义;多实例 其余实例的陈旧快照需全量覆盖)。供 notify Dispatcher 远端变更转发。
func (*Debouncer) ManagementKeys ¶
func (d *Debouncer) ManagementKeys()
ManagementKeys 管理 key(mk-)CRUD/状态变更:auth 快照全量 Reload(跨实例 收敛——本实例写面已增量 Upsert/Delete;其余实例需全量覆盖)。供 notify Dispatcher 远端变更转发。
func (*Debouncer) Multipliers ¶
func (d *Debouncer) Multipliers()
Multipliers 组倍率 / 用户-组专属倍率(price_multiplier)变更(含组创建/ 删除与 group_assignment CRUD——新倍率须即刻进快照,防 ×1 计费窗口):余额 倍率快照定向刷新(组 + assignment 两路小表单查,非全量 Reload—— EffectiveMultiplier 陈旧 ≤10s 不可接受)。
func (*Debouncer) Rules ¶
func (d *Debouncer) Rules()
Rules 规则表变更(规则 CRUD):规则表全量重载(重载清窗口计数——全实例 同步执行语义,NOTIFY 广播)。供 notify Dispatcher 远端变更转发。
func (*Debouncer) Settings ¶
func (d *Debouncer) Settings()
Settings settings 变更(UpdateSetting)→ auth 快照全量 Reload(gate 预算 按新 N 重算;≤200ms 去抖窗口与其余 Kind 一致);settings 快照本身由发布端 同步刷新(service.UpdateSetting)/远端 dispatcher 各自负责——本 mark 只承担 scope 声明方(当前 = auth,snapshots.go:30)重载。
func (*Debouncer) Stats ¶
Stats 满足 handler.StatsProvider(独立于 worker.Worker 契约;装配链路见 internal/handler/ops.go 文件头)。
func (*Debouncer) Templates ¶
func (d *Debouncer) Templates()
Templates 模板(base_url/models/映射)变更:sched 全量 + clients 失效 (base_url 变更需按新地址重建 SDK 客户端——评审发现:此前 Factory.InvalidateAll 无人调用,模板 base_url 更新后流量仍打旧上游直至 重启)。
func (*Debouncer) Users ¶
func (d *Debouncer) Users()
Users 用户 CRUD(含创建)/余额变更:auth + 余额快照全量(新用户 必须即刻进余额快照——去抖窗口内收敛,防 ≤10s 402 窗口;回归测试 tools/e2e "建用户 → <0.5s 请求 → 200")。
auth 定向回退规则:本轮不做 Auth.UpsertUser 定向刷新,先全量 Reload(加载在锁外——Auth.Reload 内部先 LoadKeys/LoadUsers 再整体换快照, 读端 RWMutex 不阻塞)。回退规则:仅当压测复测用户 fill <100/s 且 pprof 显示 auth.Reload 为热点时才新增 UpsertUser 定向路径。
type DebouncerStats ¶
type DebouncerStats struct {
Dirty bool `json:"dirty"` // 是否有待执行的重载
DirtyKinds string `json:"dirty_kinds"` // 脏位名(逗号分隔;空 = 纯组级定向)
DirtyGroups int `json:"dirty_groups"` // 组级定向账号数
WindowMs int64 `json:"window_ms"` // 去抖窗口
}
DebouncerStats 去抖器脏状态(当前是否有待执行的合并重载)。
type Kind ¶
type Kind uint8
Kind 是需要"全量重载"的脏位;纯组级定向不占位(走 State.Groups)。
const ( // KindUsers 用户 CRUD(含创建)/余额变更:auth + 余额快照全量 Reload。 KindUsers Kind = 1 << iota // KindTemplates 模板(base_url/models/映射)变更:sched 全量 + clients 失效。 KindTemplates // KindClients aiclient 工厂失效(模板 base_url / 账号 upstream_key 变更)。 KindClients // KindMultipliers 组倍率 / 用户-组专属倍率(price_multiplier)变更:余额 // 倍率快照定向刷新。 KindMultipliers // KindKeys key CRUD(创建/轮换/删除/改额度 多实例 key 缺口):auth // 快照全量 Reload(v1 不做增量定向)。 KindKeys // KindRules 规则表变更(规则 CRUD):规则表全量重载(重载清窗口计数, // 全实例同步执行语义)。 KindRules // KindSettings settings 变更(UpdateSetting)→ auth 快照全量 Reload // (gate 预算按新 N 重算);settings 快照本身由发布端同步刷新 // (service.UpdateSetting)/远端 dispatcher 各自负责——本 mark 只承担 // scope 声明方(当前 = auth,snapshots.go:30)重载。 KindSettings // KindManagementKeys 管理 key(mk-)CRUD/状态变更(多实例缺口)→ auth // 快照全量 Reload(跨实例收敛;本实例写面已增量 Upsert/Delete)。 KindManagementKeys )
type RulesReloader ¶
RulesReloader 规则表全量重载(rule.RuleEngine 实现——现有签名 Reload(ctx) error,需加 ReloadRules 适配;重载清窗口计数,全实例同步 执行语义)。未注入 nil → reloadAll 跳过。
type SchedReloader ¶
type SchedReloader interface {
InvalidateAll()
InvalidateGroup(groupID int64)
// InvalidateGroups 批量组失效(同一临界区内逐组单组重载后一次冻结发布):
// Debouncer 窗口内多组失效合并为一次调用(替代逐组 InvalidateGroup)。
InvalidateGroups(ids []int64)
}
SchedReloader 调度器快照重载(scheduler.Scheduler 实现)。