Documentation
¶
Index ¶
- Constants
- Variables
- func NormalizeSubject(scope Scope, subject string) (string, error)
- func NormalizeUserPath(raw string) (string, error)
- func PeriodBounds(now time.Time, seconds int64, settings Settings) (time.Time, time.Time)
- func PeriodLabel(seconds int64) string
- func PeriodSeconds(period string) (int64, bool)
- func ValidateSettings(settings Settings) error
- type Budget
- type CheckResult
- type ExceededError
- type MongoDBStore
- func (s *MongoDBStore) Close() error
- func (s *MongoDBStore) DeleteBudget(ctx context.Context, scope Scope, subject string, periodSeconds int64) error
- func (s *MongoDBStore) GetSettings(ctx context.Context) (Settings, error)
- func (s *MongoDBStore) ListBudgets(ctx context.Context) ([]Budget, error)
- func (s *MongoDBStore) ReplaceConfigBudgets(ctx context.Context, budgets []Budget) error
- func (s *MongoDBStore) ResetAllBudgets(ctx context.Context, at time.Time) error
- func (s *MongoDBStore) ResetBudget(ctx context.Context, scope Scope, subject string, periodSeconds int64, ...) error
- func (s *MongoDBStore) SaveSettings(ctx context.Context, settings Settings) (Settings, error)
- func (s *MongoDBStore) SumSpend(ctx context.Context, windows []SpendWindow) ([]Spend, error)
- func (s *MongoDBStore) UpsertBudgets(ctx context.Context, budgets []Budget) error
- type Result
- type SQLStore
- func (s *SQLStore) Close() error
- func (s *SQLStore) DeleteBudget(ctx context.Context, scope Scope, subject string, periodSeconds int64) error
- func (s *SQLStore) GetSettings(ctx context.Context) (Settings, error)
- func (s *SQLStore) ListBudgets(ctx context.Context) ([]Budget, error)
- func (s *SQLStore) ReplaceConfigBudgets(ctx context.Context, budgets []Budget) error
- func (s *SQLStore) ResetAllBudgets(ctx context.Context, at time.Time) error
- func (s *SQLStore) ResetBudget(ctx context.Context, scope Scope, subject string, periodSeconds int64, ...) error
- func (s *SQLStore) SaveSettings(ctx context.Context, settings Settings) (Settings, error)
- func (s *SQLStore) SumSpend(ctx context.Context, windows []SpendWindow) ([]Spend, error)
- func (s *SQLStore) UpsertBudgets(ctx context.Context, budgets []Budget) error
- type Scope
- type Service
- func (s *Service) Budgets() []Budget
- func (s *Service) Check(ctx context.Context, subjects Subjects, now time.Time) error
- func (s *Service) CheckWithResults(ctx context.Context, subjects Subjects, now time.Time) ([]CheckResult, error)
- func (s *Service) DeleteBudget(ctx context.Context, scope Scope, subject string, periodSeconds int64) error
- func (s *Service) Refresh(ctx context.Context) error
- func (s *Service) ReplaceConfigBudgets(ctx context.Context, budgets []Budget) error
- func (s *Service) ResetAll(ctx context.Context, at time.Time) error
- func (s *Service) ResetBudget(ctx context.Context, scope Scope, subject string, periodSeconds int64, ...) error
- func (s *Service) SaveSettings(ctx context.Context, settings Settings) (Settings, error)
- func (s *Service) Settings() Settings
- func (s *Service) Statuses(ctx context.Context, now time.Time) ([]CheckResult, error)
- func (s *Service) StatusesFor(ctx context.Context, subjects Subjects, now time.Time) ([]CheckResult, error)
- func (s *Service) UpsertBudgets(ctx context.Context, budgets []Budget) error
- type Settings
- type Spend
- type SpendWindow
- type Store
- type Subjects
Constants ¶
const ( PeriodHourlySeconds int64 = 3600 PeriodDailySeconds int64 = 86400 PeriodWeeklySeconds int64 = 604800 // PeriodMonthlySeconds is a sentinel key for calendar-month windows, not a literal 30-day duration. PeriodMonthlySeconds int64 = 2592000 )
const ( // SourceConfig marks budgets seeded from static configuration. SourceConfig = "config" // SourceManual marks budgets created or changed through admin APIs. SourceManual = "manual" )
Variables ¶
var ErrNotFound = errors.New("budget not found")
ErrUnavailable indicates a budget service was used without an initialized store.
Functions ¶
func NormalizeSubject ¶ added in v0.1.60
NormalizeSubject canonicalizes a budget subject for its scope. Label subjects keep their case: they are compared verbatim against the labels recorded on usage entries, the same way the usage label filter and by-label breakdown compare them.
func NormalizeUserPath ¶
func PeriodBounds ¶
func PeriodLabel ¶
func PeriodSeconds ¶
func ValidateSettings ¶
Types ¶
type Budget ¶
type Budget struct {
Scope Scope `json:"scope" bson:"scope"`
Subject string `json:"subject" bson:"subject"`
PeriodSeconds int64 `json:"period_seconds" bson:"period_seconds"`
Amount float64 `json:"amount" bson:"amount"`
Source string `json:"source,omitempty" bson:"source,omitempty"`
LastResetAt *time.Time `json:"last_reset_at,omitempty" bson:"last_reset_at,omitempty"`
CreatedAt time.Time `json:"created_at" bson:"created_at"`
UpdatedAt time.Time `json:"updated_at" bson:"updated_at"`
}
Budget stores one spend limit for one scope, subject, and reset period.
func NormalizeBudget ¶
func (Budget) SubjectLabel ¶ added in v0.1.60
SubjectLabel names the budget subject for error messages and logs.
type CheckResult ¶
type CheckResult struct {
Budget Budget `json:"budget"`
PeriodStart time.Time `json:"period_start"`
PeriodEnd time.Time `json:"period_end"`
Spent float64 `json:"spent"`
HasUsage bool `json:"has_usage"`
Remaining float64 `json:"remaining"`
}
CheckResult describes one evaluated budget limit.
func (CheckResult) PeriodRatio ¶
func (r CheckResult) PeriodRatio(now time.Time) float64
PeriodRatio returns the elapsed fraction of the budget period at now, clamped to [0, 1].
func (CheckResult) UsageRatio ¶
func (r CheckResult) UsageRatio() float64
UsageRatio returns spent/amount for the period, or 0 when the budget amount is not positive. It is deliberately not clamped: values above 1 indicate an exceeded budget.
type ExceededError ¶
type ExceededError struct {
Result CheckResult
}
ExceededError indicates a budget has already been exhausted.
func (*ExceededError) Error ¶
func (e *ExceededError) Error() string
type MongoDBStore ¶
type MongoDBStore struct {
// contains filtered or unexported fields
}
func NewMongoDBStore ¶
func (*MongoDBStore) Close ¶
func (s *MongoDBStore) Close() error
func (*MongoDBStore) DeleteBudget ¶
func (*MongoDBStore) GetSettings ¶
func (s *MongoDBStore) GetSettings(ctx context.Context) (Settings, error)
func (*MongoDBStore) ListBudgets ¶
func (s *MongoDBStore) ListBudgets(ctx context.Context) ([]Budget, error)
func (*MongoDBStore) ReplaceConfigBudgets ¶
func (s *MongoDBStore) ReplaceConfigBudgets(ctx context.Context, budgets []Budget) error
func (*MongoDBStore) ResetAllBudgets ¶
func (*MongoDBStore) ResetBudget ¶
func (*MongoDBStore) SaveSettings ¶
func (*MongoDBStore) SumSpend ¶ added in v0.1.60
func (s *MongoDBStore) SumSpend(ctx context.Context, windows []SpendWindow) ([]Spend, error)
SumSpend totals uncached spend for every window in one aggregation.
A budget check matches several budgets at once — a user-path subtree plus a budget per request label — so the pipeline matches the union of their windows once and accumulates a conditional sum per window instead of running an aggregation each.
func (*MongoDBStore) UpsertBudgets ¶
func (s *MongoDBStore) UpsertBudgets(ctx context.Context, budgets []Budget) error
type SQLStore ¶ added in v0.1.60
type SQLStore struct {
// contains filtered or unexported fields
}
SQLStore stores budgets and budget settings in a SQL database.
func NewSQLStore ¶ added in v0.1.60
NewSQLStore creates the budget tables and indexes if needed.
func (*SQLStore) DeleteBudget ¶ added in v0.1.60
func (*SQLStore) GetSettings ¶ added in v0.1.60
func (*SQLStore) ListBudgets ¶ added in v0.1.60
func (*SQLStore) ReplaceConfigBudgets ¶ added in v0.1.60
func (*SQLStore) ResetAllBudgets ¶ added in v0.1.60
func (*SQLStore) ResetBudget ¶ added in v0.1.60
func (*SQLStore) SaveSettings ¶ added in v0.1.60
func (*SQLStore) SumSpend ¶ added in v0.1.60
SumSpend totals uncached spend for every window with one scan per chunk.
A budget check matches several budgets at once — a user-path subtree plus a budget per request label — and running one statement each would scan the usage table once per budget. Conditional aggregation collapses them into a single pass: the outer WHERE spans the union of the windows, and each window gets its own SUM(CASE ...) column.
type Scope ¶ added in v0.1.60
type Scope string
Scope names what a budget limits: a consumer user-path subtree or a request label.
const ( // ScopeUserPath limits a consumer subtree; the subject is a user path and // covers all its descendants. ScopeUserPath Scope = "user_path" // ScopeLabel limits everything carrying one request label; the subject is // the label verbatim. A request carrying several labels is charged against // every matching label budget. ScopeLabel Scope = "label" )
func NormalizeScope ¶ added in v0.1.60
NormalizeScope canonicalizes a budget scope name. An empty scope means user_path, keeping pre-scope budget definitions and requests valid.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
func (*Service) CheckWithResults ¶
func (s *Service) CheckWithResults(ctx context.Context, subjects Subjects, now time.Time) ([]CheckResult, error)
CheckWithResults evaluates every budget covering the request subjects and stops at the first exhausted one, returning it as an ExceededError alongside the results evaluated so far.
func (*Service) DeleteBudget ¶
func (*Service) ReplaceConfigBudgets ¶
func (*Service) ResetBudget ¶
func (*Service) SaveSettings ¶
func (*Service) StatusesFor ¶ added in v0.1.60
func (s *Service) StatusesFor(ctx context.Context, subjects Subjects, now time.Time) ([]CheckResult, error)
StatusesFor evaluates every budget covering the request subjects without enforcing limits. Unlike CheckWithResults it never stops at an exhausted budget, so callers get the full status picture even when several are exceeded.
type Settings ¶
type Settings struct {
DailyResetHour int `json:"daily_reset_hour" bson:"daily_reset_hour"`
DailyResetMinute int `json:"daily_reset_minute" bson:"daily_reset_minute"`
WeeklyResetWeekday int `json:"weekly_reset_weekday" bson:"weekly_reset_weekday"`
WeeklyResetHour int `json:"weekly_reset_hour" bson:"weekly_reset_hour"`
WeeklyResetMinute int `json:"weekly_reset_minute" bson:"weekly_reset_minute"`
MonthlyResetDay int `json:"monthly_reset_day" bson:"monthly_reset_day"`
MonthlyResetHour int `json:"monthly_reset_hour" bson:"monthly_reset_hour"`
MonthlyResetMinute int `json:"monthly_reset_minute" bson:"monthly_reset_minute"`
UpdatedAt time.Time `json:"updated_at" bson:"updated_at"`
}
Settings controls the calendar anchors used to find the active budget period. Values are interpreted in UTC.
func DefaultSettings ¶
func DefaultSettings() Settings
DefaultSettings returns the reset anchors used when no DB setting exists.
type Spend ¶ added in v0.1.60
Spend is the total tracked cost for one SpendWindow. HasUsage is false when the window matched no priced usage at all, which keeps a budget with no traffic from ever blocking.
type SpendWindow ¶ added in v0.1.60
SpendWindow asks for the tracked spend of one budget subject over one time window.
type Store ¶
type Store interface {
ListBudgets(ctx context.Context) ([]Budget, error)
UpsertBudgets(ctx context.Context, budgets []Budget) error
DeleteBudget(ctx context.Context, scope Scope, subject string, periodSeconds int64) error
ReplaceConfigBudgets(ctx context.Context, budgets []Budget) error
GetSettings(ctx context.Context) (Settings, error)
SaveSettings(ctx context.Context, settings Settings) (Settings, error)
ResetBudget(ctx context.Context, scope Scope, subject string, periodSeconds int64, at time.Time) error
ResetAllBudgets(ctx context.Context, at time.Time) error
// SumSpend totals uncached spend for every window in one round trip, in
// the order given. Budget enforcement runs on every request, so the whole
// matching set is asked for at once rather than one query per budget.
SumSpend(ctx context.Context, windows []SpendWindow) ([]Spend, error)
Close() error
}
Store persists budget definitions, reset settings, and spend lookups.