Documentation
¶
Overview ¶
Package budget meters model spend against the policy's gateway budgets (ADR-0017). It is shared by both sides of the design: halo-server keeps the authoritative counters (Ledger), and every halo-proxy replica reports usage to it and caches its verdicts (Client). Scope keys and windows are computed here once so both sides agree.
Index ¶
- Constants
- func Cost(prices map[string]policy.ModelPrice, model string, u Usage) (usd float64, priced bool)
- func Cutoff(b *policy.Budget, now time.Time) time.Time
- func Window(b *policy.Budget, t time.Time) (start, reset time.Time)
- type Charge
- type Counters
- type Ledger
- func (l *Ledger) All(budgets []policy.Budget, now time.Time) []Status
- func (l *Ledger) Apply(budgets []policy.Budget, batch string, recs []Record, now time.Time) (duplicate bool)
- func (l *Ledger) Snapshot() (b []byte, changed bool, err error)
- func (l *Ledger) Status(budgets []policy.Budget, p Principal, now time.Time) []Status
- type Principal
- type Record
- type Spend
- type Status
- type Usage
Constants ¶
const MaxRetention = 95 * 24 * time.Hour
MaxRetention is how far back any budget policy can still count: the longest rolling period policy accepts (90 days) plus one of its buckets (period/48, under 2 days), and it covers any calendar window (a month is at most 31 days). A shared ledger drops buckets older than this regardless of which budgets a replica's policy names (TestMaxRetentionCoversPolicy).
Variables ¶
This section is empty.
Functions ¶
func Cost ¶
Cost prices u for a provider model. priced is false when the model has no price: its tokens still count toward token limits, but it costs $0.
Types ¶
type Charge ¶
type Charge struct {
Budget *policy.Budget
Key string // "user:<id>", "group:<name>", "ring:<name>" or "org"
}
Charge is one counter a request is charged to.
type Counters ¶
Counters is a ledger's counter state: budget -> key -> bucket start (unix seconds) -> spend. It is what an external store (the HA backend) persists.
type Ledger ¶
type Ledger struct {
// contains filtered or unexported fields
}
Ledger holds the authoritative counters. It lives only in halo-server, a single replica (ADR-0017), so a mutex is the whole concurrency story.
func FromCounters ¶
FromCounters is a read-only view over counters loaded from an external store, for Status and All.
func (*Ledger) All ¶
All returns every counter with spend in its current window, plus the fixed org and group counters even at zero, sorted by budget then key.
func (*Ledger) Apply ¶
func (l *Ledger) Apply(budgets []policy.Budget, batch string, recs []Record, now time.Time) (duplicate bool)
Apply charges every record to the counters its principal maps to under budgets. A batch id already applied within the last hour is ignored and reported as a duplicate. Records are trusted to be validated by the caller.
type Principal ¶
type Principal struct {
Subject string `json:"subject,omitempty"`
Groups []string `json:"groups,omitempty"`
Ring string `json:"ring,omitempty"`
}
Principal is who a request is charged to: the verified subject (empty when anonymous) with its IdP groups, and the ring the gateway routed it to. It never comes from client-supplied headers (invariant 4).
type Record ¶
Record is usage a gateway replica observed for one principal. At is the minute it happened, so usage reported late (after an outage) still lands in the window it belongs to.
type Status ¶
type Status struct {
Budget string `json:"budget"`
Scope string `json:"scope"`
Key string `json:"key"`
Window string `json:"window"`
Period string `json:"period,omitempty"`
Action string `json:"action"`
LimitUSD float64 `json:"limitUSD,omitempty"`
LimitTokens int64 `json:"limitTokens,omitempty"`
SpentUSD float64 `json:"spentUSD"`
SpentTokens int64 `json:"spentTokens"`
AlertAt []float64 `json:"alertAt,omitempty"`
// ResetAt is when the counter drops below its limit again: the next
// calendar window, or for rolling windows when enough old usage expires.
ResetAt time.Time `json:"resetAt"`
}
Status is one counter's state in its current window.
func (Status) Utilization ¶
Utilization is the larger of spent/limit over USD and tokens (0 when unlimited).