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