Skip to content

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.

gh release create v1.0.0 --notes "Release" || gh release edit v1.0.0 --notes "Release"

Force Overwrite

Don't check, just overwrite. Safe when overwriting with identical content is acceptable.

git push --force-with-lease origin "$BRANCH"

Unique Identifiers

Generate deterministic IDs so duplicate operations target the same resource.

BRANCH="update-$(sha256sum file.txt | cut -c1-8)"

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.

MARKER=".completed-$RUN_ID"
[ -f "$MARKER" ] && exit 0
# Do work...
touch "$MARKER"

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.

Comments