AXIAM PHP SDK

RetryPolicy
in package

FinalYes

Bounded read-only retry policy — CONTRACT.md §16.

This SDK had no §16 policy before D5 — only §9's single-flight refresh coordination, which is a different mechanism (OidcClient's for ($attempt = 0; $attempt < 3; $attempt++) loop coordinates concurrent refreshes; it does not retry a transport failure). §11.2 rule 5 and §14.2 rule 6 had both been requiring "the SDK's existing bounded read-only retry policy" against a policy that did not exist here.

Table of Contents

Constants

BASE_DELAY_MS  : mixed = 200.0
First backoff step, in milliseconds (§16.1).
MAX_ATTEMPTS  : mixed = 3
Attempt cap: 1 initial + 2 retries (§16.1).
MAX_DELAY_MS  : mixed = 5000.0
Ceiling on any single computed backoff, in milliseconds (§16.1).

Methods

backoffMs()  : float
The un-jittered backoff for a 1-based attempt: `min(MAX_DELAY_MS, BASE_DELAY_MS * 2^(n-1))`.
delayMs()  : float
The actual wait: **full jitter** over `[0, backoff]`, raised to any server-supplied `Retry-After` (§16.1).
execute()  : T
Runs `$operation` under the §16 policy.

Constants

BASE_DELAY_MS

First backoff step, in milliseconds (§16.1).

public mixed BASE_DELAY_MS = 200.0

MAX_ATTEMPTS

Attempt cap: 1 initial + 2 retries (§16.1).

public mixed MAX_ATTEMPTS = 3

MAX_DELAY_MS

Ceiling on any single computed backoff, in milliseconds (§16.1).

public mixed MAX_DELAY_MS = 5000.0

Methods

backoffMs()

The un-jittered backoff for a 1-based attempt: `min(MAX_DELAY_MS, BASE_DELAY_MS * 2^(n-1))`.

public static backoffMs(int $attempt) : float

Attempt 1 → 200ms, attempt 2 → 400ms.

Parameters
$attempt : int

The 1-based attempt number.

Return values
float

The backoff in milliseconds.

delayMs()

The actual wait: **full jitter** over `[0, backoff]`, raised to any server-supplied `Retry-After` (§16.1).

public static delayMs(int $attempt, float $retryAfterMs, float $fraction) : float

Full jitter, not backoff ± 10%. Partial jitter keeps every client's retries clustered around the same instant, which is the thundering herd retries are supposed to prevent rather than cause.

Retry-After is a floor, never a ceiling: the server is stating when it will be ready, so retrying sooner is not permitted — and a Retry-After: 0 cannot shorten the wait below what jitter chose.

Parameters
$attempt : int

The 1-based attempt that just failed.

$retryAfterMs : float

A server-supplied hint in milliseconds, or 0.0.

$fraction : float

The jitter draw in [0, 1], injected so tests can pin it.

Return values
float

The wait in milliseconds.

execute()

Runs `$operation` under the §16 policy.

public static execute(string $operationName, bool $enabled, TelemetryDispatcher $telemetry, callable(int): T $operation[, callable(): float|null $jitter = null ][, callable(float): void|null $sleep = null ][, callable(NetworkError): bool|null $retryable = null ]) : T

$operation receives the 1-based attempt number so it can label its §19 request pair — §19.2 rule 5 requires one pair per attempt so a caller can count real wire calls, and passing 1 every time would make a retried call indistinguishable from a single slow one.

$operation MUST be side-effect-free. This helper — like every retry helper — cannot tell the difference, so routing a mutation through it would silently duplicate a side effect, or replay a single-use credential (an authorization code, a device code at redemption, a rotating refresh token) into a hard invalid_grant.

Only NetworkError is retried. The §2 taxonomy folds 408/429/5xx/transport into that one type, so this implements the whole §16.3 table: AuthError and AuthzError are decisive answers from the server, not transport failures.

Parameters
$operationName : string

Canonical name, for the §19 event.

$enabled : bool

§16.1 disable switch.

$telemetry : TelemetryDispatcher

Notified before each retry wait.

$operation : callable(int): T

The side-effect-free operation.

$jitter : callable(): float|null = null

Injected jitter draw, for tests.

$sleep : callable(float): void|null = null

Injected sleep, for tests.

$retryable : callable(NetworkError): bool|null = null

Decides whether a caught NetworkError is eligible at all; null keeps the previous behaviour of retrying every one. CONTRACT.md §27 needs this for two reasons: §27.4 rule 8 retries only GET, and §27.4 rule 7 puts ValidationError UNDER NetworkError, so a body the server has already rejected would otherwise be sent three times.

Tags
template
Return values
T
On this page

Search results