invalidate

package
v0.0.1-beta.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 28, 2026 License: AGPL-3.0 Imports: 7 Imported by: 0

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

View Source
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

type AuthReloader interface {
	Reload(ctx context.Context) error
}

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 New

func New(cfg Config) *Debouncer

New 构造去抖器(reloadAll 目标经 cfg 注入)。

func (*Debouncer) Accounts

func (d *Debouncer) Accounts(gids []int64, keyChanged bool)

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

func (d *Debouncer) Close(ctx context.Context) error

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) Multipliers

func (d *Debouncer) Multipliers()

Multipliers 组倍率 / 用户-组专属倍率(price_multiplier)变更(含组创建/ 删除与 group_assignment CRUD——新倍率须即刻进快照,防 ×1 计费窗口):余额 倍率快照定向刷新(组 + assignment 两路小表单查,非全量 Reload—— EffectiveMultiplier 陈旧 ≤10s 不可接受)。

func (*Debouncer) Name

func (d *Debouncer) Name() string

Name 满足 worker.Worker 契约。

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) Start

func (d *Debouncer) Start(ctx context.Context) error

Start 启动执行 goroutine(幂等:重复 Start 返回错误;worker 契约)。

func (*Debouncer) Stats

func (d *Debouncer) Stats() any

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
)

type RulesReloader

type RulesReloader interface {
	ReloadRules(ctx context.Context) error
}

RulesReloader 规则表全量重载(rule.RuleEngine 实现——现有签名 Reload(ctx) error,需加 ReloadRules 适配;重载清窗口计数,全实例同步 执行语义)。未注入 nil → reloadAll 跳过。

type SchedReloader

type SchedReloader interface {
	InvalidateAll()
	InvalidateGroup(groupID int64)
}

SchedReloader 调度器快照重载(scheduler.Scheduler 实现)。

type State

type State struct {
	Kinds  Kind
	Groups map[int64]struct{} // 组级定向(账号变更的受影响组)
}

State 一次到点执行的合并脏集合(同窗口多实体变更并集)。 包含关系:full(KindTemplates 的 sched 全量)⊇ 组级定向 ⊇ 无——模板变更 与账号组变更同窗口时跳过组级重载(reloadAll)。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL