🔧 Programmierung 🕛 vor 1 Monat 4 Min Lesezeit
0

Make an Outbox Relay Lease Expire Without Violating Delivery Invariants

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Relay A claims outbox row 42 and publishes its message. Before A records completion, its lease expires. Relay B claims row 42 and publishes it again. Both relays behaved according to their local state; the broker received a duplicate.



A lease prevents unlimited concurrent ownership. It cannot create exactly-once delivery across a database and broker without a shared transaction.



The honest contract is:




Every committed outbox event is eventually offered at least once; consumers preserve business invariants under duplicate offers.







State model






CODE
pending
-> leased(owner, token, expires_at)
-> published

leased --expiry--> claimable
leased --failure--> claimable






A fencing token increments on every claim:




CODE
UPDATE outbox
SET lease_owner = :worker,
lease_token = lease_token + 1,
lease_expires_at = now() + interval '30 seconds'
WHERE id = :id
AND published_at IS NULL
AND (lease_expires_at IS NULL OR lease_expires_at < now())
RETURNING id, event_id, payload, lease_token;






Completion is conditional:




CODE
UPDATE outbox
SET published_at = now()
WHERE id = :id
AND lease_owner = :worker
AND lease_token = :token
AND published_at IS NULL;






The token stops stale relay A from marking B's newer lease complete. It does not retract A's already published message.






Minimal event-order simulator



Model actions instead of threads:




CODE
state = {
"token": 0,
"lease": None,
"published": False,
"broker": [],
}


def claim(worker):
state["token"] += 1
state["lease"] = (worker, state["token"])
return state["token"]


def send(worker, token):
state["broker"].append({"event": "e42", "worker": worker, "token": token})


def complete(worker, token):
if state["lease"] == (worker, token):
state["published"] = True


a = claim("A")
send("A", a)
# Time advances; A's lease expires.
b = claim("B")
send("B", b)
complete("A", a) # fenced out
complete("B", b)

assert len(state["broker"]) == 2
assert state["published"] is True






The duplicate is not a simulator bug. It is the counterexample that defines the consumer requirement.






Consumer invariant



Suppose the event awards a $10 credit. The wrong handler performs an unconditional increment twice. A robust handler stores event identity in the same transaction as the business effect:




CODE
BEGIN;

INSERT INTO consumed_events (consumer, event_id)
VALUES ('credit-service', 'e42')
ON CONFLICT DO NOTHING;

-- Continue only when the insert affected one row.
UPDATE accounts SET credit_cents = credit_cents + 1000 WHERE id = :account;

COMMIT;






The invariant is not “the handler ran once.” It is:




CODE
For each (consumer, event_id), the credit effect commits at most once.






Other event types need different invariants. A state projection can use monotonic versions. A notification may need a delivery ledger. A cache invalidation can be naturally idempotent. Do not apply one generic deduplication recipe without naming the business effect.






Failure classes to inject




































Event order Expected property
send, crash, lease expiry, resend one business effect
claim A, expire, claim B, A completes stale completion rejected
broker acknowledgement lost resend allowed
consumer commits effect, acknowledgement lost redelivery causes no second effect
duplicate arrives concurrently uniqueness constraint serializes effect
event arrives after newer version projection does not move backward


Generate permutations around claim, send, complete, consume, and acknowledge. The acceptance rule should inspect durable state, not log-line counts.






Tradeoffs






































Mechanism Helps Does not solve
relay lease bounded ownership, crash recovery post-send ambiguity
fencing token stale database completion duplicate broker message
broker deduplication duplicates within broker window long delays or consumer effects
consumer inbox effect deduplication unbounded retention
monotonic version stale projection updates additive non-idempotent effects


Inbox retention must cover the maximum plausible redelivery interval. Deleting deduplication records after one day while a dead-letter queue retains messages for a week reopens old effects.






Limits



This model assumes the source transaction atomically writes domain state and the outbox row. It does not address event ordering across aggregates, broker partition changes, poison messages, or multi-region conflict resolution. Those require additional invariants.



Exactly-once can sometimes be provided inside one technology boundary. Across independently failing database, relay, broker, and consumer boundaries, state the narrower guarantee and test the violating event order. For this protocol, lease expiry after send is the sequence every design must survive.

Vollständiger Original-Artikel
Den kompletten Beitrag mit allen Details direkt auf dev.to lesen.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
6 Quellen
CVE-2022-44255 | TOTOLINK LR350 9.3.5u.6369_B20220309 buffer overflow (EUVD-2022-47204)
2 Quellen
CVE-2026-68426 | Linux Kernel up to 6.18.41/7.1.5/7.2-rc3 xfrm validate_xmit_skb_list use after free (Nessus ID 346426)
1 Quelle
Windows 11 Probleme mit gültiger Domänenanmeldung nach September-Update [Workaround]
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Make an Outbox Relay Lease Expire Without Violating Delivery Invariants

Thematisch verwandte Begriffe: Make, Outbox, Relay, Lease · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...