Esta página foi traduzida por máquina e ainda não foi revisada por uma pessoa. O inglês é a referência; correções são bem-vindas no GitHub. GitHub

Cookwala / SDK e cenários / 050

The same execution id with a new Idempotency-Key is a 409 conflict

The Idempotency-Key makes a retry safe; the execution id makes the run unique. Reusing the id with a different key is a conflict, while the original key still returns the original run.

Público: developer · Objetivo: Robôs para pessoas · Nível: beginner

Leia primeiro: /docs/CORE/ /docs/HUB/

Passos

  1. Start a run with key ex-050-dup-k1. startExecution

  2. Send the same request with a different key. The id already exists, so the answer is a Problem with title conflict. startExecution

  3. The first run advances to the step that needs a person.

  4. Send it again with the original key: the hub returns the first run, at its current state. startExecution

Resultado

You know how the two identifiers divide the work: one for retries, one for the run. Next: scenario 051 moves to the catalog side with an incident report.

Linha de comando

cookwala hub --recipes examples --speed 200
jq '. + {"x-hub-human-present": true}' examples/core/execute-request.json | curl -s -X POST http://localhost:7878/v1/executions -H 'Content-Type: application/json' -H 'Idempotency-Key: ex-2026-10-04-001-a' -d @-
jq '. + {"x-hub-human-present": true}' examples/core/execute-request.json | curl -s -X POST http://localhost:7878/v1/executions -H 'Content-Type: application/json' -H 'Idempotency-Key: ex-2026-10-04-001-b' -d @-

Saída gravada

Status: ok

[1] startExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "ex-050-dup", "seq": 0, "state": "accepted", "request": "ex-050-dup", "updatedAt": "2026-10-07T00:54:31Z", "x-hub-plan": [{"node": "n1", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n2", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n3", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n4", "op": "cw.op.heat", "by": "human", "verifiedBy": "human"}, {"node": "n5", "op": "cw.op.saute", "by": "huma…
[2] startExecution: {"type": "https://cookwala.ai/errors/conflict", "title": "conflict", "detail": "execution id already exists"}
[4] startExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "ex-050-dup", "seq": 6, "state": "needs_human", "request": "ex-050-dup", "updatedAt": "2026-10-07T00:54:33Z", "x-hub-plan": [{"node": "n1", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n2", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n3", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n4", "op": "cw.op.heat", "by": "human", "verifiedBy": "human"}, {"node": "n5", "op": "cw.op.saute", "by": "h…

Código

Executar: python scenarios/out/050-duplicate-execution-id-is-a-conflict/python.py

# Scenario 050: The same execution id with a new Idempotency-Key is a 409 conflict
# The Idempotency-Key makes a retry safe; the execution id makes the run unique. Reusing the id with a different key is a conflict, while the original key still returns the original run.
# Run a hub first: python hub/cookwala_hub.py --recipes examples
import json, os
from cookwala.client import CookwalaClient, CookwalaProblem

def load(path):
    with open(path, encoding="utf-8") as f:
        return json.load(f)

def pick(obj, path):
    for part in path.replace("]", "").replace("[", ".").split("."):
        obj = obj[int(part)] if part.isdigit() else (len(obj) if part == "length" else obj.get(part))
    return obj

c = CookwalaClient(os.environ.get("COOKWALA_HUB", "http://localhost:7878"))


# Step 1: Start a run with key ex-050-dup-k1.
try:
    first = c.start_execution({"core": "0.2.0", "kind": "ExecuteRequest", "id": "ex-050-dup", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "servings": 4, "requestedBy": "agent:planner-1", "idempotencyKey": "ex-050-dup-a"}, "ex-050-dup-k1", True)
except CookwalaProblem as p:
    first = p.body  # a refusal is a result, not a crash
    print("refused:", p.refusal)
assert pick(first, "state") == "accepted", pick(first, "state")
print("ok", "state", "=", "accepted")
assert pick(first, "id") == "ex-050-dup", pick(first, "id")
print("ok", "id", "=", "ex-050-dup")

# Step 2: Send the same request with a different key. The id already exists, so the answer is a Problem with title conflict.
try:
    conflict = c.start_execution({"core": "0.2.0", "kind": "ExecuteRequest", "id": "ex-050-dup", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "servings": 4, "requestedBy": "agent:planner-1", "idempotencyKey": "ex-050-dup-a"}, "ex-050-dup-k2", True)
except CookwalaProblem as p:
    conflict = p.body  # a refusal is a result, not a crash
    print("refused:", p.refusal)
assert pick(conflict, "title") == "conflict", pick(conflict, "title")
print("ok", "title", "=", "conflict")
assert pick(conflict, "detail") == "execution id already exists", pick(conflict, "detail")
print("ok", "detail", "=", "execution id already exists")

# Step 3: The first run advances to the step that needs a person.
import time; time.sleep(4)

# Step 4: Send it again with the original key: the hub returns the first run, at its current state.
try:
    retry = c.start_execution({"core": "0.2.0", "kind": "ExecuteRequest", "id": "ex-050-dup", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "servings": 4, "requestedBy": "agent:planner-1", "idempotencyKey": "ex-050-dup-a"}, "ex-050-dup-k1", True)
except CookwalaProblem as p:
    retry = p.body  # a refusal is a result, not a crash
    print("refused:", p.refusal)
assert pick(retry, "id") == "ex-050-dup", pick(retry, "id")
print("ok", "id", "=", "ex-050-dup")
assert pick(retry, "state") == "needs_human", pick(retry, "state")
print("ok", "state", "=", "needs_human")
assert pick(retry, "seq") == 6, pick(retry, "seq")
print("ok", "seq", "=", 6)

print("scenario complete")

scenarios/050-duplicate-execution-id-is-a-conflict.json

Anterior: 049 Próximo: 051