Skip to content

Idempotent Handler Checklist

Idempotency key flow

ChokaQ provides at-least-once execution. A handler can run more than once if a worker crashes after user code produces a side effect but before finalization is stored. Make every side-effecting handler idempotent.

Required Decisions

QuestionRecommended answer
What is the business idempotency key?Use order ID, invoice ID, webhook event ID, payment attempt ID, or another stable domain key.
Where is the key enforced?Prefer the system that owns the side effect: database unique constraint, provider idempotency key, or outbox.
How long can duplicates arrive?Set idempotency TTL from business reality, not from retry settings alone.
What happens after partial side effects?Store enough state to retry safely or send the job to manual review.

Patterns

  • Database unique constraint plus upsert.
  • Payment/email/webhook provider idempotency key.
  • Outbox table for local transaction plus later publish.
  • Read-before-write when repeating the handler converges to the same state.
  • Manual review for operations that cannot be made safe to repeat.

ChokaQ Middleware Boundary

The optional idempotency middleware writes an InProgress claim before handler execution, skips concurrent duplicates, and writes a completion marker after success. It reduces duplicate handler execution for one active key, but it does not make external systems exactly-once.

Relevant metrics:

MetricOutcome examples
chokaq.idempotency.claimsclaimed, completed, completed_duplicate, in_progress_duplicate, released, complete_conflict, empty_key

Investigate complete_conflict: it means handler execution finished, but the completion marker could not be stored for that key/job pair.

Architecture Decision

Why this pattern?

At-least-once execution is honest but pushes duplicate side-effect safety to the business boundary. Idempotent handlers are the application-level answer.

Trade-offs

Idempotency adds data modeling and retention decisions. The cost is necessary for payments, email, webhooks, and external writes.

Alternatives considered

AlternativeBenefitCost
Trust queue exactly-onceSimple.False assumption for real crashes.
Disable retriesAvoids retry duplicates.Loses resilience and still does not solve crash windows.
Provider idempotency onlyStrong where available.Not every dependency supports it.

Additional Questions

Why is handler idempotency required?
Because a job can execute more than once after crash/recovery.

What is the hardest duplicate window?
External side effect succeeds, then the process crashes before ChokaQ archives the job.

What should payment jobs use?
A provider-supported idempotency key tied to the business payment attempt.

Apache 2.0 Licensed