Skip to content

PATTERN Cited by 1 source

Delayed secondary with lock check

Pattern

In an active-active architecture where both regions receive the same event simultaneously, introduce a configurable delay on the secondary handler's queue. After the delay expires, the secondary checks a shared lock store:

  1. If the primary has already processed the event → skip (idempotency check passes).
  2. If the primary has NOT processed it (failure/timeout) → acquire the lock and execute (failover).

The delay gives the primary region a deterministic time window to claim the event first, converting what would be a race condition into an ordered priority with automatic failover.

Mechanism

Event ──┬──→ Primary SQS (immediate) ──→ Lambda: acquire lock → execute → respond
        └──→ Secondary SQS (delay: T) ──→ Lambda: check lock → skip OR acquire → execute

The lock is a conditional write (e.g., DynamoDB PutItem with ConditionExpression: attribute_not_exists(pk)) in a globally-replicated store. The delay T must exceed the expected primary processing time plus cross-region replication lag.

Trade-offs

Pro Con
No duplicate execution despite active-active Delay T adds latency to failover path
Primary gets first-mover advantage deterministically Replication lag can cause split-brain if T is too short
No manual failover intervention needed Extra cost for dual-region infrastructure at steady state
Retries are safe — lock + idempotency record prevents re-execution Presigned URLs or tokens may expire during extended delays

When to use

  • Multi-region event processing where exactly-once semantics matter (e.g., external API calls, database mutations, billing events).
  • Custom resource handlers, webhook processors, or any fan-out architecture where duplicate side effects are unacceptable.
  • When you need sub-minute automated failover without the complexity of a full consensus protocol.

Seen in

Last updated · 590 distilled / 1,788 read