eqixiacEquinix Infrastructure as Code

Retries, timeouts and rate limits

What the transport retries and what it never retries, 401 recovery, the 429 path, the circuit breaker, and the fixed timeouts.

Default retry policy#

RetryPolicy.defaultPolicy() applies to every client unless EquinixConfig supplies another.

PropertyDefault
Retries after the first attempt3
Retryable statuses429, 500, 502, 503, 504
Transport IOExceptionRetried
BackoffExponential with full jitter, base 500 ms, cap 20 s
Retry-AfterHonoured, as delta-seconds or an HTTP-date

Idempotency rule#

A 5xx response or an IOException does not say whether the server processed the request, and a create that is sent again after the server processed it produces a second resource. The SDK therefore retries those failures only for idempotent methods, which it defines as every method except POST and PATCH. PATCH is excluded because the SDK sends RFC 6902 documents, and an add operation applied twice changes the result.

A 429 response states that the server did not process the request, so the SDK retries a 429 for every method, as long as 429 is in the retryable set.

FailureGET, PUT, DELETEPOST, PATCH
429RetriedRetried
500, 502, 503, 504RetriedNot retried
IOExceptionRetriedNot retried
Any other 4xxNot retriedNot retried

Under this rule the default policy does not retry a POST .../search on a 5xx, although a search has no side effect. A client that sends only reads can enable retries for POST and PATCH.

Java
import com.eqixiac.equinix.EquinixConfig;
import com.eqixiac.equinix.Fabric;
import com.eqixiac.equinix.core.http.RetryPolicy;

RetryPolicy readOnlyPolicy = RetryPolicy.builder()
    .maxRetries(5)
    .baseDelayMillis(250)
    .maxDelayMillis(10_000)
    .retryableStatusCodes(Set.of(429, 500, 502, 503, 504))
    .retryOnIoException(true)
    .honorRetryAfter(true)
    .retryNonIdempotentMethods(true)      // only for a client that sends no creates or patches
    .build();

Fabric reader = new Fabric(credentials, EquinixConfig.builder().retryPolicy(readOnlyPolicy).build());
Fabric noRetries = new Fabric(credentials, EquinixConfig.builder().retryPolicy(RetryPolicy.none()).build());

Do not set retryNonIdempotentMethods(true) on a client that creates resources. The Equinix APIs covered here define no idempotency key.

401 recovery New in 4.0#

When an authenticated request is answered with HTTP 401, the client discards the cached token, obtains a new one and replays the request once. If the replayed request is also answered with 401, the client throws EquinixAuthenticationException. When several concurrent requests are rejected with the same token, the client sends one token request for all of them.

The replay is safe for every method, because a 401 means the request was rejected before it was processed. There is no replay for the token request itself, for the operations declared unauthenticated (the STS exchange and discovery), or when the client has no token source.

With a BearerTokenProvider the recovery calls the provider again. A provider built with BearerTokenProvider.of(token) returns the same token, so the second attempt also fails and the exception propagates.

Rate limits#

The SDK has no client-side request throttle. It handles an HTTP 429 response as follows.

  • A 429 is retried up to the policy's limit, waiting for the Retry-After value when the response carries one and for the computed backoff otherwise.
  • When the retries are exhausted the client throws EquinixRateLimitException. Its getHttpHeaders() map carries the response headers, including Retry-After.
  • A 429 does not count as a failure for the circuit breaker.

A batch job that fans out over many resources should bound its own concurrency. The connection pool allows 20 connections per route and 50 in total, which is the upper bound on parallel requests per session.

PeeringDB, which Peering Intelligence queries, has its own limit. Anonymous access allows about 20 requests per minute. On 2026-11-11 PeeringDB throttled anonymous calls from the test account for about an hour.

Circuit breaker#

The circuit breaker is disabled by default. When enabled, one breaker counts consecutive failures across all requests of a client.

Java
import com.eqixiac.equinix.Equinix;
import com.eqixiac.equinix.core.exception.CircuitOpenException;
import com.eqixiac.equinix.core.http.CircuitBreaker;

EquinixConfig config = EquinixConfig.builder()
    .circuitBreaker(new CircuitBreaker(5, 30_000))    // threshold, cooldown in ms
    .build();

try (Equinix eq = new Equinix(credentials, config)) {
    eq.fabric().ports().list();
} catch (CircuitOpenException e) {
    // no HTTP exchange took place; the breaker is open
}
StateBehaviour
CLOSEDRequests pass. A 5xx response or an IOException increments the counter. Any completed exchange with a status below 500 resets it. At the threshold the breaker opens.
OPENEvery request fails at once with CircuitOpenException until the cooldown elapses. Results of requests admitted before the breaker opened are ignored.
HALF_OPENOne probe request is admitted. Its success closes the breaker and its failure opens it for another cooldown. A probe slot expires after a further cooldown, so a probe that never reports cannot block the breaker.

Each retry attempt also passes through the breaker. A 4xx response is not counted as a failure, because the service answered the request.

Timeouts#

TimeoutValue
Connect10 s
Socket read60 s
Lease a pooled connection5 s

These values are constants of the HTTP client, and EquinixConfig has no option for them in the current tree. The worst case for one idempotent call under the default policy is four attempts of up to 60 s each plus up to three backoff waits of at most 20 s each.

The live rate-card adapters in the design layer use their own client with 5 s connect and 10 s socket timeouts, see Cost and value.

Correlation identifiers#

The client assigns one X-Correlation-Id header value to each logical request and sends the same value on every retry attempt. The value appears in the debug log and on EquinixServiceException.getCorrelationId(), so a failed call can be matched to its log lines and quoted in a support case.