Skip to content

Retries

Which calls are safe to repeat, when a repeat may help, and what to do when a write's outcome is unknown.

Updated

Arbol’s SDKs send each call once and never retry it, so your code decides. Two questions decide it: may a repeat succeed, which the error’s retryable answers, and is a repeat safe, which the operation’s effect answers.

Each operation’s effect

Every operation’s page in the API reference states its Effect:

Effect What the operation does Repeating it
Reads Changes nothing. Safe.
Writes Creates or changes something. Safe only if the operation is idempotent, or once you’ve confirmed the first attempt didn’t apply.
Deletes Deletes or cancels something. Same as a write.

The HTTP method doesn’t tell you the effect. agenda.bookings.lookup is a POST that reads, and agenda.bookings.cancel is a POST that deletes: read the operation’s Effect instead.

When a repeat may help

error.retryable says whether repeating the same request may succeed. These common codes are retryable:

Status code What to do
429 RATE_LIMITED Too many requests from this credential. Wait the seconds in Retry-After, then repeat.
503 UPSTREAM_UNAVAILABLE Back off, then repeat.
504 UPSTREAM_TIMEOUT Back off, then repeat a read. A write may have applied: see below.

Services add retryable codes of their own, such as PROVIDER_UNAVAILABLE in gMedic, SURA and Visoft. When retryable is false, the same request will fail again: change the input, the credential or the state first.

Writes with an unknown outcome

Some failures don’t say whether a write happened:

  • 502 OUTCOME_UNKNOWN: the operation may have been applied. Check its result before repeating it.
  • A timeout, or no answer at all. A write that ended with 504 UPSTREAM_TIMEOUT, or whose connection dropped, may have applied too.

Reconcile before you repeat: read the record, or list what the first attempt would have created. Several operations say so in their description, such as gmedic.patients.create (“reconcile an unknown outcome before repeating”), visoft.appointments.create (“Never repeat a booking whose outcome is unknown”) and raiz.channels.create, which isn’t idempotent: list the channels before trying again.

The Rust SDK labels every failure with an outcome: Refused (nothing happened), NotSent (the request never left) or Unknown (a write that may have happened).

Operations that are safe to repeat

Some writes are designed to be repeated:

  • Idempotent operations. An operation’s Effect says idempotent when repeating it with the same input has no further effect, and not idempotent when a repeat may act again. Among writes, raiz.agents.update and agenda.waitlist.join are idempotent, while raiz.contacts.create and sura.appointments.create aren’t. MCP clients see the same as the tool’s idempotentHint.
  • Idempotency keys. agenda.appointments.create takes an idempotencyKey, unique within the organization: reusing it returns the original appointment. sura.appointments.create takes one too, reused only for the same accepted offer.
  • Repeats that change nothing. Calling agenda.waitlist.join again for the same patient, service and reason returns the same open entry. Cancelling a Raíz task again with raiz.tasks.cancel changes nothing.
  • Version checks. Updates that take expectedVersion apply only if the record hasn’t changed since you read that version. In Raíz, repeating an update that already applied fails with VERSION_CONFLICT instead of applying twice.

Pending answers in SURA

A SURA call may answer "status": "pending" with an operationId and retryAfterSeconds instead of its result, while SURA finishes an earlier request. The operation keeps running. After retryAfterSeconds, get the result with sura.operations.get, or repeat the identical call, which returns the same operation instead of starting another.

A retry policy

  1. Respect retryable: false. Fix the request before sending it again. The exception is OUTCOME_UNKNOWN: check whether the write applied, and repeat it only if it didn’t.
  2. Repeat reads when retryable is true, or when no answer came back.
  3. Repeat writes and deletes only when the operation is idempotent, or once you’ve confirmed the first attempt didn’t apply.
  4. Wait between attempts. Use Retry-After when the answer has it. Otherwise, back off exponentially with jitter, and cap the number of attempts.
  5. Log each attempt’s X-Request-Id, so a failure can be traced.

Type to search…

↑↓ navigate↵ selectEsc close