Implementation Patterns¶
Six patterns for making operations idempotent. Each has tradeoffs; choose based on your constraints.
Pattern Overview¶
| Pattern | Best For | Tradeoff |
|---|---|---|
| Check-Before-Act | Creating resources | Race conditions possible |
| Upsert | APIs with atomic operations | Not universally available |
| Force Overwrite | Content that can be safely replaced | Destructive if misused |
| Unique Identifiers | Natural deduplication | ID logic can be complex |
| Deduplication | Preventing duplicate operations at a boundary | Requires enforcement at the right layer |
| Tombstone Markers | Multi-step operations | Markers need cleanup |
Quick Reference¶
Check-Before-Act¶
The most common pattern. Check if the target state exists before attempting to create it.
if git ls-remote --heads origin "$BRANCH" | grep -q "$BRANCH"; then
git checkout -B "$BRANCH" "origin/$BRANCH"
else
git checkout -b "$BRANCH"
fi
Create-or-Update (Upsert)¶
Use APIs or commands that handle both cases atomically.
Force Overwrite¶
Don't check, just overwrite. Safe when overwriting with identical content is acceptable.
Unique Identifiers¶
Generate deterministic IDs so duplicate operations target the same resource.
Deduplication¶
Enforce at the boundary where the duplicate would otherwise land: storage, request, or event.
INSERT INTO subscriptions (tenant_id, plan_code)
VALUES ($1, $2)
ON CONFLICT (tenant_id, plan_code) DO NOTHING;
Tombstone/Marker Files¶
Leave markers indicating operations completed.
Choosing a Pattern¶
flowchart TD
A[Need idempotency] --> K{Preventing a duplicate<br/>at a system boundary?}
K -->|Yes| L[Use Deduplication]
K -->|No| B{API has upsert?}
B -->|Yes| C[Use Upsert]
B -->|No| D{Safe to overwrite?}
D -->|Yes| E[Use Force Overwrite]
D -->|No| F{Natural unique key?}
F -->|Yes| G[Use Unique Identifiers]
F -->|No| H{Multi-step operation?}
H -->|Yes| I[Use Tombstone Markers]
H -->|No| J[Use Check-Before-Act]
%% Ghostty Hardcore Theme
style A fill:#5e7175,color:#f8f8f3
style K fill:#fd971e,color:#1b1d1e
style L fill:#f92572,color:#f8f8f3
style B fill:#fd971e,color:#1b1d1e
style C fill:#a7e22e,color:#1b1d1e
style D fill:#fd971e,color:#1b1d1e
style E fill:#e6db74,color:#1b1d1e
style F fill:#fd971e,color:#1b1d1e
style G fill:#65d9ef,color:#1b1d1e
style H fill:#fd971e,color:#1b1d1e
style I fill:#9e6ffe,color:#1b1d1e
style J fill:#65d9ef,color:#1b1d1e
| Scenario | Recommended Pattern |
|---|---|
| Creating resources (PRs, branches, files) | Check-Before-Act |
| Updating existing resources | Upsert or Force Overwrite |
| Operations with natural keys | Unique Identifiers |
| Preventing duplicate rows, requests, or event handling | Deduplication |
| Complex multi-step operations | Tombstone Markers |
| API supports atomic operations | Upsert |
Combine Patterns
Real-world automation often combines multiple patterns. A workflow might use Check-Before-Act for PR creation, Force Overwrite for branch updates, Unique Identifiers for naming, and Deduplication at the storage layer underneath it all.