httppolicy

package
v0.18.1 Latest Latest
Warning

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

Go to latest
Published: Aug 26, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package httppolicy is the host-neutral HTTP retry and usage policy shared by origin clients (Atlassian via atlhttp, Linear). It owns which statuses are retryable, backoff plus Retry-After, the error-body snippet, the response byte cap, and the Usage/Meter counters.

It deliberately does not own Base/Auth/path joining (atlhttp's host pin: the Authorization header never leaves the configured site), Linear's bare-key Authorization header, Linear's x-ratelimit-* headers, or rejected-credential sentinels. ErrAuth stays per host family so Linear need not share atlhttp.ErrAuth (GDK-274).

Index

Constants

View Source
const DefaultBackoff = time.Second

DefaultBackoff is the first retry wait; Wait doubles it per attempt up to MaxWait.

View Source
const DefaultRetries = 5

DefaultRetries is the production attempt budget origin clients apply in New.

View Source
const DefaultTimeout = 60 * time.Second

DefaultTimeout is the HTTP client timeout origin clients apply in New.

View Source
const MaxBody int64 = 64 << 20

MaxBody is the response-body cap applied with io.LimitReader. Both atlhttp.DoRaw and linear.Client.gql used 64<<20; one constant keeps them from drifting.

View Source
const MaxWait = 30 * time.Second

MaxWait is the ceiling on exponential backoff. Retry-After seconds replace the backoff outright and are not themselves capped here — matching the previous atlhttp/linear wait() bodies.

Variables

This section is empty.

Functions

func IsRetryable

func IsRetryable(code int) bool

IsRetryable is the read-path retry set: throttle and transient server errors. 501 and 505 are answers, not transients. Writes use IsRetryableWrite — a 500 may mean the mutation applied.

func IsRetryableWrite

func IsRetryableWrite(code int) bool

IsRetryableWrite is the mutating retry set: 429 and 503 only.

func Snippet

func Snippet(b []byte) string

Snippet trims and truncates a response body for error messages.

func Wait

func Wait(ctx context.Context, backoff time.Duration, attempt int, retryAfter string, meter *Meter) error

Wait sleeps for the retry delay: backoff<<attempt, capped at MaxWait, replaced by a positive Retry-After (integer seconds; Atoi). A non-nil meter records the time actually spent. Cancel stops the wait and is still recorded.

Types

type Meter

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

Meter holds atomic counters shared by concurrent request goroutines. A Client is used from up to 4 concurrent sync workers (contracts/sync.md).

func (*Meter) NoteRequest

func (m *Meter) NoteRequest()

NoteRequest records one HTTP attempt that left the process.

func (*Meter) NoteRetry

func (m *Meter) NoteRetry()

NoteRetry records an attempt re-sent after a wait.

func (*Meter) NoteStatus

func (m *Meter) NoteStatus(code int)

NoteStatus classifies a completed HTTP status into Throttled (429) or ServerErrors (other 5xx).

func (*Meter) NoteWait

func (m *Meter) NoteWait(d time.Duration)

NoteWait records time actually spent in Wait. Non-positive durations are ignored.

func (*Meter) Snapshot

func (m *Meter) Snapshot() Usage

Snapshot returns the current counters without resetting them. Same shape as store.DB.PoolStats / WriteBusyRetries: a cheap accessor, no logs.

func (*Meter) Take

func (m *Meter) Take() Usage

Take returns the current counters and zeroes the numeric fields so a flusher can accumulate into daily totals without double-counting.

LastThrottledAt is a timestamp, not a counter: it is included in the snapshot but is NOT cleared. The in-process "last 429" stays visible until the process exits or a later 429 overwrites it.

type Usage

type Usage struct {
	Requests        int64
	Throttled       int64     // 429 responses
	ServerErrors    int64     // 5xx responses, excluding 429
	Retries         int64     // attempts re-sent after a wait
	WaitMS          int64     // milliseconds actually spent in Wait
	LastThrottledAt time.Time // UTC; zero if never throttled
}

Usage is a point-in-time snapshot of outbound HTTP traffic for one origin client. Counters are process-local until a caller persists them (see store.api_usage).

Requests counts every HTTP attempt, including retries: that is the unit that draws from the site's rate budget. This is our own call volume, not the remaining point pool — the site does not expose that.

Jira, Confluence, and Linear all report this type so an operator can compare "linear throttled us" against "Jira throttled us" field by field (Snapshot / Take / Client.Usage / Client.TakeUsage). LastThrottledAt is the shared name; WaitMS is milliseconds actually spent in Wait.

Jump to

Keyboard shortcuts

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