Skip to content

Add idempotency keys, Retry-After and opt-in retries - #6

Merged
imronreviady merged 1 commit into
mainfrom
idempotency-keys
Oct 3, 2026
Merged

imronreviady merged 1 commit into
mainfrom
idempotency-keys

Conversation

@imronreviady

Copy link
Copy Markdown
Collaborator

Why

Integrators had no safe way to retry: no idempotency key, no Retry-After on errors, no retry policy (#2). The API now accepts Idempotency-Key on enrolment and batch endpoints (LiveXFace/backend#7) and replays the first outcome for an identical repeat.

What changed

  • idempotency_key= on faces.register, batch_register, batch_register_async
  • livexface.new_idempotency_key()
  • LiveXFaceApiError.retry_after
  • client arguments max_retries (default 0) and max_retry_delay (default 60 s)
  • Retries are off by default. When enabled: 429 and 503 wait for Retry-After (capped) or exponential backoff with full jitter; network errors and other 5xx are retried only for GET/PATCH/DELETE and keyed requests; other 4xx never. Enrolment and batch calls generate one key per call when retries are on and reuse it on every attempt.
  • README: "Idempotent requests" and "Production retries" sections.

Verification

  • Tests for: 429 with Retry-After: 12 exposing status/code/requestId/retryAfter with one request; 503 then 201 retried after 5 s with the same generated key; dropped connection then replay with the same key; 422 not retried; caller key sent / no header when off; two distinct v4 keys; unkeyed POST not retried on a network error or 500 but retried on 503.
  • mypy livexface and pytest (18 passed) on Python 3.10 and 3.12.
  • Live against the API: enrolling twice with one key and retries on returned the same face id, and the collection held one face.

Closes #2

Enrolment, synchronous batch and asynchronous batch calls take an
idempotency key, sent as the Idempotency-Key header, and a generator
returns a random UUID v4 for it. The API replays the first outcome for
an identical repeat, so a retry after a lost response cannot enrol
twice.

The typed API error now carries retryAfter, the seconds from a
Retry-After header.

Retries are off by default. When enabled with a maximum number of
retries: 429 and 503 wait for Retry-After (capped, default 60 s) or an
exponential backoff with jitter; network errors and other 5xx are
retried only for GET, PATCH and DELETE and for keyed requests; other
4xx are never retried. Enrolment and batch calls generate one key per
call when retries are on and none was given, and send it on every
attempt.
@imronreviady
imronreviady merged commit 08bcedd into main Oct 3, 2026
2 checks passed
@imronreviady
imronreviady deleted the idempotency-keys branch October 3, 2026 11:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support idempotency keys and Retry-After aware transient error handling

1 participant