Een applicatie slaat een bericht van een klant op en publiceert vervolgens een gebeurtenis voor een worker. Als de applicatie tussen deze twee handelingen vastloopt, bestaat het bericht wel, maar krijgt de worker er nooit iets van mee. Als de volgorde wordt omgedraaid, ontstaat er een ander probleem: de gebeurtenis kan al bestaan terwijl de wijziging in de database nog niet is doorgevoerd.
De transactionele uitbox lost dit probleem van dubbele schrijfbewerkingen op door de zakelijke wijziging en een uitgaande gebeurtenis in dezelfde databasetransactie op te slaan. Dat is een waardevolle garantie, maar het zorgt er niet voor dat de gehele workflow precies één keer wordt uitgevoerd.
Zorg ervoor dat de eerste garantie nauwkeurig is
Als de transactie wordt vastgelegd, bestaan zowel het domeinrecord als het outbox-record. Als de transactie wordt teruggedraaid, zou geen van beide mogen bestaan. Een afzonderlijke relay leest de outbox en publiceert gebeurtenissen naar de broker.
In de AWS-beschrijving van het patroon wordt ingegaan op deze transactiegrens en de noodzaak om dubbele berichten te verwerken. Ik vind het nuttig om deze garanties vast te leggen voordat ik een keuze maak voor een relay-implementatie.
Een outbox-record moet een vast gebeurtenis-ID, tenantcontext, gebeurtenistype, schemaversie en de domeinverwijzing bevatten die consumenten nodig hebben. Of er een volledige momentopname of een verwijzing wordt opgenomen, hangt af van het doel van de gebeurtenis en de vereisten op het gebied van consistentie.
Het relais heeft nog steeds een crashvenster
Stel dat het relais een gebeurtenis met succes publiceert, maar crasht voordat de rij in de uitbox als verzonden wordt gemarkeerd. Bij de volgende poging kan het relais de gebeurtenis opnieuw publiceren. Als de gebeurtenis vóór de publicatie als verzonden zou worden gemarkeerd, zou het risico bestaan dat deze verloren gaat.
Ik ga er daarom vanuit dat de consument duplicaten kan ontvangen. Meerdere relay-workers hebben ook een strategie nodig voor het claimen van gegevens, die ongecontroleerde conflicten voorkomt en tegelijkertijd herstel mogelijk maakt wanneer een worker uitvalt.
De publicatiestatus moet informatie bevatten over pogingen, het tijdstip waarop de volgende poging kan worden ondernomen en de laatste bruikbare foutmelding. Een steeds groter wordende uitbox is een achterstand die moet worden onderzocht, en geen gezonde wachtrij, louter omdat de database invoer accepteert.
Maak consumenten idempotent op de bedrijfsgrens
Voor een consument wiens bewerking betrekking heeft op de lokale database, kan ik het ID van de verwerkte gebeurtenis vastleggen en de bewerking in één transactie uitvoeren. Een uniekheidsbeperking voorkomt dat twee gelijktijdige bewerkingen dezelfde operatie twee keer uitvoeren.
Externe effecten zijn lastiger. Als de consument een e-mail verstuurt of een betalingsactie uitvoert, kan de database-transactie de externe dienst niet omvatten. Voor die bewerking is een idempotentiesleutel van de provider, een duurzaam bewerkingsrecord of een afstemmingspad voor onzekere uitkomsten nodig.
De instellingen voor de levering door de broker heffen deze applicatielimiet niet op. In een JetStream-consumer moeten het gedrag bij bevestiging en herlevering overeenkomen met het moment waarop de applicatie het werk veilig als voltooid kan beschouwen. Raadpleeg de documentatie van de NATS-consumer om deze werkwijze voor de geïmplementeerde configuratie te controleren.
Bepaal welke volgorde het domein nodig heeft
Een globale volgorde is vaak duur en overbodig. Een gesprek kan een eigen volgorde vereisen, terwijl niet-gerelateerde gesprekken onafhankelijk van elkaar kunnen verlopen. Ik geef er de voorkeur aan om die domeineis te formuleren, in plaats van te vertrouwen op de toevallige volgorde waarin werknemers hun taken afronden.
Consumenten kunnen een geaggregeerde versie of reeks gebruiken om hiaten en verouderde gebeurtenissen op te sporen. Het herstelbeleid bepaalt vervolgens of er moet worden gewacht, of dat de definitieve status opnieuw moet worden geladen, of dat er een herhaling moet worden aangevraagd.
Ook de versiebeheer van schema’s is van belang. Een bericht dat tijdens een implementatie in de broker is achtergebleven, kan afkomstig zijn van oudere code. Consumenten hebben een compatibiliteitsplan nodig voor de versies die nog steeds kunnen worden geleverd.
Het hele traject bedienen
Ik houd de leeftijd van de oudste nog niet gepubliceerde gebeurtenis, publicatiefouten, vertraging bij de consument, herhaalde leveringen en het aantal ‘dead-letter’-berichten bij. Deze statistieken geven verschillende storingspunten weer en mogen niet worden samengevoegd tot één totaal voor de wachtrij.
Mijn faaltests schakelen het relais uit na publicatie, stoppen de consumer na het optreden van het neveneffect en spelen een opgenomen gebeurtenis opnieuw af. Elke test controleert of het systeem zich kan herstellen zonder dat de beoogde werking verloren gaat of het effect ervan wordt versterkt.
De uitbox biedt de applicatie een blijvende toezegging om gegevens te publiceren. Gebruikers en downstream-integraties moeten die toezegging nog wel bruikbaar maken.
Bijgewerkt op 25 september 2026.