Octri

Retries and timeouts

Every generated client retries failed requests with exponential backoff, and limits how long each attempt can take. You don't have to configure any of it: these settings are for when the defaults don't fit your API.

Settings

Set these project-wide under Reliability in SDK Studio, or on one endpoint when a method needs different treatment. Configure nothing and every language ships with the defaults below. The generated README states the policy that package actually ships with.

Max attemptsnumberdefault: 3

Total tries, including the first, from 1 to 10.

reliability.maxAttempts

Base backoffmillisecondsdefault: 500

The first retry's delay, before jitter. Up to 120,000, which is 2 minutes.

reliability.backoffMs

Max backoffmillisecondsdefault: 8000

The ceiling on any single delay. Up to 600,000, which is 10 minutes.

reliability.maxBackoffMs

Retry status codeslist of status codesdefault: 408, 425, 429, 500, 502, 503, 504

Which HTTP statuses can trigger a retry: any from 100 to 599. See what gets retried for the rule on POST.

reliability.retryOn

Timeoutmillisecondsdefault: 30000

How long one attempt can take. Up to 600,000, which is 10 minutes.

reliability.timeoutMs

Leave a field blank and the client keeps its built-in default. A value that can't work is dropped rather than shipped, so a blank field and a 0 timeout both leave the layer beneath in charge.

Max attempts counts the first try

1 disables retries. 3 means the original request plus two retries.

Precedence

Each layer overrides the one before it, field by field. An endpoint that sets only Timeout keeps your project's Max attempts.

  1. The built-in defaults

    The policy in the table above.

  2. Your project default

    Set in SDK Studio. Applies to every method.

  3. A per-endpoint override

    Set in SDK Studio. Applies to one method.

  4. The developer's client config

    Set when they create the client.

  5. The developer's per-call option

    Set on a single call.

What developers can change

Whatever you ship is a default. A developer using your SDK can override it for their client or for one call:

typescript
const client = new Acme({
  auth: { bearer: process.env.API_TOKEN! },
  timeoutMs: 10_000,
  retry: { maxAttempts: 5 },
});

const user = await client.users.get(
  { id: "usr_1" },
  { timeoutMs: 2_000, retry: { maxAttempts: 1 } },
);

What gets retried

Being on the Retry status codes list isn't always enough. The method matters too.

RequestFailed with a listed statusFailed with a network error or timeout
GET, HEAD, PUT, DELETE, OPTIONSRetriedRetried
POST, PATCHOnly on 429 and 503Only if your spec declares an idempotency header on the operation. See idempotency
POST is not retried on a 500

A 500 from a POST may mean the write happened. The clients don't retry it, even if you add 500 to the list, because a 429 or 503 is the only status that says plainly the request wasn't processed.

Backoff

The delay doubles with each attempt, starting from Base backoff, with up to one Base backoff of random jitter added. That way, clients that fail together don't all retry in step and overload a recovering service. Max backoff caps the result.

If your API sends a Retry-After header, the client uses that instead, as a number of seconds or a date. It's still capped by Max backoff.

Keep Max backoff above your longest Retry-After

With a Max backoff of 8 seconds, a server asking for 60 seconds gets 8, and the retry arrives too soon. If you rate-limit by the minute, raise the ceiling.

Timeouts

Timeout limits one attempt, not the whole call. Three attempts at 30 seconds can take over 90 seconds against a dead server, plus the backoff between them.

A 0 doesn't disable the timeout. It's ignored, and the default applies. For a long-running call, set a long timeout on that endpoint.

Errors after retries run out

When the attempts are used up, the caller gets a typed error. These names are from TypeScript, and most languages match them closely.

ErrorMeaning
SdkTimeoutErrorAn attempt ran past its timeout
SdkNetworkErrorDNS, connection, TLS or socket failure
SdkRateLimitError429
SdkInternalServerErrorAny 5xx
SdkHttpErrorAny other non-2xx response. It's the parent of the status errors

HTTP errors carry the status code, body, headers and, when your server sends one, the request ID. Go uses errors.Is(err, ErrRateLimit) against sentinels rather than subclasses.

typescript
try {
  await client.users.get({ id: "usr_1" });
} catch (error) {
  if (error instanceof SdkNotFoundError) {
    return null;
  }
  if (error instanceof SdkHttpError) {
    console.error(error.statusCode, error.requestId);
  }
  throw error;
}

Log the request ID when you can. It's the quickest way to match a failed call with your server's traces.

From the CLI

octri sdk settings set reliability.maxAttempts 5 changes one value. The keys are in the settings reference, and the command in SDK commands.