apibudget

package
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 26, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

SPDX-License-Identifier: MIT Package apibudget accounts for and bounds the provider HTTP requests a query consumes. It works at the transport layer rather than at call sites, which gives exact counts (including pagination and retries), covers every existing provider path without touching one of them, and puts rate-header capture in a single place.

The mechanism is internal; only its data shape (model.CostReport) is public, keeping the public API minimal.

Index

Constants

This section is empty.

Variables

View Source
var ErrBudgetExceeded = errors.New("api request budget exceeded")

ErrBudgetExceeded is returned instead of dispatching a request once the configured ceiling has been consumed. Callers branch on it with errors.Is to convert a budget stop into a partial result plus a disclosure rather than a failure.

It surfaces through http.Client wrapped in a *url.Error, which unwraps, so errors.Is keeps working end to end.

Functions

func Unmetered

func Unmetered(ctx context.Context) context.Context

Unmetered marks requests made with the returned context as not counting against the ceiling.

It exists for endpoints the provider itself does not charge — GitHub's /rate_limit is the motivating case. Charging a free pre-flight check against the user's request budget would both misstate what the query cost and make a small explicit ceiling unusable, since the check would consume it before any evidence could be gathered.

Rate headers from an unmetered response are still recorded: the observation is exactly what the request was for.

Types

type Transport

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

Transport counts every request it dispatches, refuses to dispatch beyond a ceiling, and records the rate-limit headers from every response.

A ceiling of 0 disables the cap but keeps counting: accounting is never optional, only enforcement is.

func NewTransport

func NewTransport(next http.RoundTripper, ceiling int) *Transport

NewTransport wraps next, counting and bounding the requests that pass through it. A nil next uses http.DefaultTransport. ceiling <= 0 means uncapped.

func (*Transport) Ceiling

func (t *Transport) Ceiling() int

Ceiling reports the configured cap; 0 means uncapped.

func (*Transport) Consumed

func (t *Transport) Consumed() int

Consumed reports how many requests have been dispatched.

func (*Transport) QuotaSeen

func (t *Transport) QuotaSeen() bool

QuotaSeen reports whether any response carried rate-limit headers.

func (*Transport) Remaining

func (t *Transport) Remaining() int

Remaining reports how many more requests the ceiling permits. It returns math.MaxInt when uncapped.

This is the check-before-dispatch accessor: a concurrent fan-out asks how much it can afford and dispatches only a batch it can fully pay for, rather than firing requests and letting the losers fail. Without that, which requests won the race would decide which commits got enriched, and the same query could return different results run to run.

func (*Transport) Report

func (t *Transport) Report() model.CostReport

Report snapshots consumption and the latest quota observation. It is safe to call at any point, including on an early-return path — a query that stopped early must still report what it spent.

func (*Transport) RoundTrip

func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip implements http.RoundTripper.

Jump to

Keyboard shortcuts

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