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 ¶
const DefaultBackoff = time.Second
DefaultBackoff is the first retry wait; Wait doubles it per attempt up to MaxWait.
const DefaultRetries = 5
DefaultRetries is the production attempt budget origin clients apply in New.
const DefaultTimeout = 60 * time.Second
DefaultTimeout is the HTTP client timeout origin clients apply in New.
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.
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 ¶
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 ¶
IsRetryableWrite is the mutating retry set: 429 and 503 only.
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 ¶
NoteStatus classifies a completed HTTP status into Throttled (429) or ServerErrors (other 5xx).
func (*Meter) NoteWait ¶
NoteWait records time actually spent in Wait. Non-positive durations are ignored.
func (*Meter) Snapshot ¶
Snapshot returns the current counters without resetting them. Same shape as store.DB.PoolStats / WriteBusyRetries: a cheap accessor, no logs.
func (*Meter) Take ¶
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.