Idempotency and Retry-Safe Automation

Who this is for

Developers writing automation scripts or webhook handlers that must be safe to retry without causing duplicate operations.

What you will complete

Understand idempotency in the context of CloudAIPilot webhooks and API calls, and apply patterns that make your automation safe to re-run.


What is idempotency?

An operation is idempotent if running it multiple times produces the same result as running it once. This matters for automation because:

  • Webhooks may be delivered more than once (retries after timeout, provider re-delivery)
  • CI pipelines may be re-triggered accidentally
  • Network failures may cause an API call to be retried when the original actually succeeded

Without idempotency, duplicate triggers can cause duplicate deployments, multiple backup operations, or conflicting configuration changes.


CloudAIPilot webhook idempotency

Each webhook payload includes an event ID and a timestamp. Use the event ID to deduplicate:

processed_events = set()  # In production, use a persistent store (Redis, DB)

def handle_webhook(payload):
    event_id = payload.get("event_id")  # or similar unique field
    
    if event_id in processed_events:
        # Already processed — return 200 but do nothing
        return {"status": "already_processed"}
    
    processed_events.add(event_id)
    # Process the event
    process(payload)
    return {"status": "ok"}

Always return 200 for already-processed events. Returning an error causes CloudAIPilot to retry the delivery, triggering another duplicate.


API call idempotency

For API calls that trigger operations, be aware of which operations are naturally idempotent and which are not:

Naturally idempotent (safe to retry):

  • GET requests (read data)
  • Checking operation status
  • Updating a configuration value (setting the same value again has no side effect)

Not naturally idempotent (retry with caution):

  • POST to trigger a new deployment (each call creates a new deployment)
  • POST to create an on-demand backup (each call creates a new backup)
  • DELETE operations (second call may return 404 — handle gracefully)

Safe retry pattern for triggering deployments:

Before triggering a deployment, check if one is already in progress:

CURRENT_STATUS=$(curl -s -H "Authorization: Bearer $TOKEN" \
  "https://api.cloudaipilot.com/v1/sites/$SITE_ID/deployments/latest" \
  | jq -r '.status')

if [ "$CURRENT_STATUS" = "running" ]; then
  echo "Deployment already in progress — skipping trigger"
  exit 0
fi

# Safe to trigger new deployment
curl -X POST -H "Authorization: Bearer $TOKEN" \
  "https://api.cloudaipilot.com/v1/sites/$SITE_ID/deploy"

Handling 409 Conflict responses

CloudAIPilot returns 409 Conflict when you attempt to start an operation that is already running (e.g., a backup when a backup is already in progress). Treat 409 as a signal to wait, not as an error:

RESPONSE_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
  -H "Authorization: Bearer $TOKEN" \
  "https://api.cloudaipilot.com/v1/servers/$SERVER_ID/backup")

if [ "$RESPONSE_CODE" = "409" ]; then
  echo "Operation already in progress — waiting for it to complete"
  # Poll for completion, then proceed
fi

Related articles