Documentation
¶
Overview ¶
Package allowance is a tenant's own fuel budgets inside its tenant budget.
An allowance is a named budget a tenant defines for part of its work — one per customer, team, agent or feature, whatever the tenant's own unit is — as `{name, fuel, per}`: so much fuel per UTC hour, day or month. A request enters an allowance (`txco://allowance/enter`), and from then on its fuel is charged to that allowance as well as to the tenant. When the window's fuel is spent the chassis refuses the request through the shared admission marker (`429 allowance_exhausted`, Retry-After = the window's end), the same path a tenant rate limit takes, so every head renders it in its own protocol.
The tenant's own budget is untouched: allowance usage is still the tenant's usage, and whichever runs out first refuses.
Definitions and counters live in the tenant's KV under chassis-reserved namespaces, so the author-facing txco://kv/* ops can neither read nor reset them. Counters are charged from the usage path (Tee), so everything that bills a request — its own line, resumed continuation segments, attachment heartbeats — fills the allowance it ran under.
Index ¶
- Constants
- func ValidName(s string) bool
- type Def
- type Period
- type Status
- type Store
- func (s *Store) Charge(ctx context.Context, tenant, name string, fuel int64) error
- func (s *Store) Def(ctx context.Context, tenant, name string) (Def, bool, error)
- func (s *Store) Delete(ctx context.Context, tenant, name string) error
- func (s *Store) List(ctx context.Context, tenant, after string, limit int) (defs []Def, next string, err error)
- func (s *Store) Set(ctx context.Context, tenant string, d Def) error
- func (s *Store) Status(ctx context.Context, tenant, name string) (Status, error)
- type Tee
Constants ¶
const ( NamespaceDefs = kv.ReservedNamespacePrefix + ".allowance" NamespaceUsed = kv.ReservedNamespacePrefix + ".allowance.used" )
Chassis-reserved KV namespaces (kv.IsReservedNamespace), so the author- facing txco://kv/* ops refuse them: definitions keyed by name, counters keyed by "<name>@<window id>".
const DefaultPeriod = Day
DefaultPeriod windows the counters of an allowance that was entered but never defined (metered, not limited).
const FlushInterval = time.Second
FlushInterval is how often the Tee writes accumulated charges to the KV. It bounds how stale an allowance's counter is for the next request's check.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Period ¶
type Period string
Period is an allowance's window: fixed UTC hours, days or months.
func ParsePeriod ¶
ParsePeriod accepts "hour" | "day" | "month".
type Status ¶
type Status struct {
Name string
Defined bool
Fuel int64 // the limit; 0 when not defined
Per Period
Used int64
ResetsAt time.Time
}
Status is one allowance's current window. Defined is false for a name that was never set: such an allowance is metered (Used counts) but not limited.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store reads and writes allowances in a tenant's KV. Safe for concurrent use.
func NewStore ¶
NewStore returns a Store over k. Pass a kv.KV with no TTL ceiling: a month window's counter must outlive any operator cap on author TTLs.
func (*Store) Charge ¶
Charge adds fuel to the allowance's current window. The window follows the definition's period (cached briefly); an undefined allowance is counted by DefaultPeriod.
func (*Store) List ¶
func (s *Store) List(ctx context.Context, tenant, after string, limit int) (defs []Def, next string, err error)
List returns one page of definitions in name order after the cursor; next is "" when there are no more.
func (*Store) Set ¶
Set creates or replaces a definition. Its counters are kept: raising the limit mid-window frees what is left of the window at once.
type Tee ¶
type Tee struct {
// contains filtered or unexported fields
}
Tee is a usage.Sink in front of the configured one. Every event goes on to the next sink unchanged; a billable event that ran under an allowance also adds its fuel to that allowance's counter. Charges are summed in memory and written once per FlushInterval per allowance, so a busy allowance costs one KV increment a second, not one per request.
func (*Tee) Close ¶
Close stops the loop, writes what is pending within ctx, then closes the wrapped sink.
func (*Tee) WriteEvent ¶
func (t *Tee) WriteEvent(ev usage.UsageEvent)
WriteEvent forwards ev and, when it is billable fuel spent under an allowance, adds it to the pending charges.