Help us shape the future of Go! Take the 2026 Go Developer Survey

budget

package
v0.23.2 Latest Latest
Warning

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

Go to latest
Published: Oct 29, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package budget 提供预算/配额记账原语(#16):按维度累计消耗,超限内容 进存档而非丢弃,消费方可按引用取回、按龄清理。

与仓内流控面(ratelimit/shedding/breaker)的丢弃式语义互补:那些原语 保护资源(超限即拒),本包保全内容(超限存档可取回)。典型场景:LLM 输出预算(超限截断提示 + 完整原文按需拉取)、日志/审计留存配额、批量 抓取字节配额。

并发安全;按龄清理依赖可注入时钟(WithClock),确定性测试不依赖 sleep。

Package budget 提供预算/配额记账原语(#16)——超限不丢、可取回、按龄清理。

与仓内丢弃式流控面(ratelimit/shedding/breaker 保护资源)互补:本包面向 「外部输出放进预算框」的记账语义——模型输出预算(超限截断提示 + 完整原文 按需拉取)、日志/审计留存配额、批量抓取字节配额。

最小面(并发安全):

l := budget.NewLedger(map[budget.Dimension]int64{"bytes": 100},
    budget.WithClock(clk.Now)) // 可注入时钟,确定性测试
ref, err := l.Consume("bytes", 250, fullOutput)
if errors.Is(err, budget.ErrOverBudget) {
    archived := l.Get(ref) // 完整原文按需取回
}
l.Sweep(time.Hour) // 按龄清理,防存档无界增长

语义要点:超限消耗不计入(内容未通过预算框);未声明维度不限量; Get 只读不删,清理由 Sweep 负责。

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidAmount = errors.New("budget: negative amount")

ErrInvalidAmount 表示消耗量为负(非法记账)。

View Source
var ErrOverBudget = errors.New("budget: over budget")

ErrOverBudget 表示本次消耗超出维度预算:content 已存档,返回值 Ref 可取回。

Functions

This section is empty.

Types

type Dimension

type Dimension string

Dimension 是预算维度(如 "bytes"/"calls";调用方自定义)。

type Ledger

type Ledger struct {
	// contains filtered or unexported fields
}

Ledger 记账器:按维度累计消耗,超限内容进存档。

func NewLedger

func NewLedger(caps map[Dimension]int64, opts ...Option) *Ledger

NewLedger 创建记账器。caps 是各维度预算上限(拷贝存储,调用方后续修改 无影响);未声明的维度不限量(仅记账语义不存在,不会误拦)。

func (*Ledger) Consume

func (l *Ledger) Consume(d Dimension, n int64, content []byte) (Ref, error)

Consume 记一笔消耗。

  • 未超限:used[d] += n,返回 (0, nil);
  • 超限:消耗不计入(内容未通过预算框),content 存档,返回 (Ref, ErrOverBudget)——Ref 经 Get 取回完整内容;
  • n < 0 返回 (0, ErrInvalidAmount)。

未声明维度不限量,恒返回 (0, nil)。

溢出安全:判据**不用** `used+n > cap`。那是 int64 上的先加后比——n 接近 math.MaxInt64 时加法回绕成负数 ⇒ 判据恒为「未超限」⇒ 该笔被直接放行 且计数器被写成负数 ⇒ 此后该维度**永久**变成「无限制」。改用不溢出的形式 `n > cap-used`(used<=cap 时 cap-used>=0,不存在回绕),并对累加做饱和 钳制(#104)。

func (*Ledger) Get

func (l *Ledger) Get(ref Ref) ([]byte, bool)

Get 按引用取回存档内容(只读,不删除;清理由 Sweep 负责)。 引用不存在(或已被清理)返回 (nil, false)。

func (*Ledger) Sweep

func (l *Ledger) Sweep(olderThan time.Duration) int

Sweep 清理入档时间早于 olderThan 的存档,返回清理条数。 olderThan=0 清理全部。

func (*Ledger) Used added in v0.23.0

func (l *Ledger) Used(d Dimension) int64

Used 返回某维度当前已消耗量(未声明维度返回 0)。

观测口:没有它,计数器异常(如被写成负数)只能靠「突然所有请求都不再被 拦」反推——而那正是预算已经失效的表现(#104)。

type Option

type Option func(*Ledger)

Option 配置 Ledger。

func WithClock

func WithClock(now func() time.Time) Option

WithClock 注入时钟(按龄清理与入档时间的确定性测试入口; 与 batch.WithBatchClock / shedding.WithShedderClock 同形)。

type Ref

type Ref uint64

Ref 是存档内容的取回引用(0 表示无存档)。

Jump to

Keyboard shortcuts

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