Retry a start safely
A request to start a run can fail on its way back, after the run started: a dropped connection, say. Send each start with an idempotency key. A start repeated with the same key, once the first request has answered, returns the run the first one started instead of starting a second one.
kindgi runs start --flow=acme.review-order --input='{"orderId":"A-100"}' --idempotency-key=order-A-100-reviewRun it twice: both print the same run, with the same id and createdAt.
From your app, pass idempotencyKey (idempotency_key in Python):
import { KindgiApiError } from '@kindgi/sdk/client';
const start = () => kindgi.runs.start({ flow: 'acme.review-order', input: { orderId: 'A-200' }, idempotencyKey: 'review-A-200', });
const first = await start();const retry = await start(); // the same start again, after the first answeredconsole.log(first.id === retry.id, retry.status);
try { await kindgi.runs.start({ flow: 'acme.review-order', input: { orderId: 'A-100' }, // a different request, same key idempotencyKey: 'review-A-200', });} catch (err) { if (err instanceof KindgiApiError) console.log(err.error.code, err.message);}true completedconflict Idempotency-Key was reused with a different request body. Use a fresh key or the original body.from kindgi.client import ConflictError
def start(): return kindgi.runs.start( flow="acme.review-order", input={"orderId": "A-200"}, idempotency_key="review-A-200" )
first = start()retry = start() # the same start again, after the first answeredprint(first.id == retry.id, retry.status)
try: kindgi.runs.start( flow="acme.review-order", input={"orderId": "A-100"}, # a different request, same key idempotency_key="review-A-200", )except ConflictError as err: print(err)True completedIdempotency-Key was reused with a different request body. Use a fresh key or the original body.How it works
Section titled “How it works”-
A request with a key Kindgi has seen gets the first request's response again: the same run, as it was returned then. Call
getfor its current state. -
A repeat sent while the first request is still running doesn't run again. It's refused with a conflict,
idempotency-key-in-flight, andRetry-After: 5:{"code":"idempotency-key-in-flight","message":"A request with this Idempotency-Key is still running. Retry after it answers (Retry-After), and you'll get its answer."}Retry after the first one answers, and you get its answer: the same run. The clients don't retry it on their own. A request that stops without answering (its runtime crashed, say) frees its key within 30 seconds.
-
The key must come with the same request. The same key with a different body (another input, other options) is refused with a conflict, and nothing starts, also while the first is still running.
-
Only an answer that succeeded is kept. A start that was refused (a flow that isn't registered yet,
404 flow-not-found) isn't, so once you've fixed the cause, the same start with the same key runs. -
Keys are kept for 24 hours, per tenant and per caller: the same key from someone else (another person, another API key) is their own request, and never gets your response.
-
A response that carries a secret (a new API key, a session token or a console session, a generated webhook signing secret) isn't kept. A retry with its key is refused with a conflict,
idempotency-key-replay-withheld, saying when the first one succeeded. It never gets the secret again, and nothing is made twice.
A waited start answers only when its run completes, fails or waits for
something, so a repeat gets idempotency-key-in-flight until then. Start a run that
can take long in the background (wait: false, whose answer carries the
run's id at once) and follow it instead.
Pick a key that names the work, not the attempt: review-A-200 for "review
order A-200", the same on every retry. A new key per attempt defeats it.
Other requests that change something (cancel, registering a webhook
endpoint, …) take an idempotency key too.