Poison messages, retries και dead-letter topics στο Boomi Event Streams
Γιατί ένα προβληματικό event μπλοκάρει έναν consumer, πώς το λύνουν τα περιορισμένα retries και ένα dead-letter topic, και πώς τα υλοποιείτε και κάνετε replay με το Boomi Event Streams.
Τα events order.created κυλούν ομαλά από το e-shop προς την αποθήκη, την τιμολόγηση και το CRM. Ένα πρωί φτάνει μια
παραγγελία για τον πελάτη C-1042, που υπάρχει στο e-shop αλλά όχι ακόμη στο ERP. Ο consumer της τιμολόγησης
αποτυγχάνει, το event ξαναστέλνεται, αποτυγχάνει ξανά, και ξανά. Σε αυτό το άρθρο εξηγούμε τι κάνει ένα τέτοιο
poison message σε ένα event-driven integration, το pattern με retries και dead-letter που το περιορίζει, και πώς
το υλοποιείτε με το Boomi Event Streams.
Τι κάνει ένα poison message
Σε ένα event-driven σύστημα, ο consumer επιβεβαιώνει (acknowledge) ένα event αφού το επεξεργαστεί. Αν η επεξεργασία αποτύχει και το event δεν επιβεβαιωθεί, ο broker το παραδίδει ξανά. Αυτό ακριβώς θέλετε για ένα προσωρινό πρόβλημα, όπως ένα restart του ERP. Και αυτό ακριβώς δεν θέλετε για ένα μόνιμο:
- Το ίδιο event ξαναδοκιμάζεται ατελείωτα, γεμίζει τα logs και σπαταλά πόρους του runtime.
- Ανάλογα με τον broker και τις ρυθμίσεις, μπορεί να καθυστερεί τα events που ακολουθούν, οπότε μία κακή παραγγελία καθυστερεί όλες τις καλές.
- Αν κάποιος το «λύσει» επιβεβαιώνοντας και τις αποτυχίες, η παραγγελία εξαφανίζεται σιωπηλά και ανακαλύπτεται όταν ο πελάτης ζητήσει το τιμολόγιο.
Το pattern: ταξινόμηση, λίγα retries, μετά dead-letter
Ταξινομήστε το σφάλμα
Δεν αξίζει κάθε αποτυχία retry. Ένας χρήσιμος διαχωρισμός:
| Είδος | Παραδείγματα | Τι κάνετε |
|---|---|---|
| Προσωρινό | Timeout του ERP, HTTP 503, απόρριψη σύνδεσης, κλείδωμα εγγραφής | Retry με καθυστέρηση |
| Μόνιμο | Ο πελάτης δεν βρέθηκε, λάθος ΑΦΜ, JSON με λάθος μορφή, άγνωστος κωδικός είδους | Αμέσως σε dead-letter |
Πέντε retries σε ένα μόνιμο σφάλμα απλώς καθυστερούν το αναπόφευκτο και προσθέτουν θόρυβο.
Λίγα, συγκεκριμένα retries
Για τα προσωρινά σφάλματα, κάντε μικρό, σταθερό αριθμό retries με αυξανόμενη καθυστέρηση (π.χ. μετά από 10 δευτερόλεπτα, 1 λεπτό, 5 λεπτά). Αν το σφάλμα επιμένει, αντιμετωπίστε το προς το παρόν ως μόνιμο.
Παραμερίστε το: το dead-letter topic
Ένα dead-letter topic (DLT) είναι ένα κανονικό topic όπου πηγαίνουν τα events που απέτυχαν, μαζί με πληροφορίες για το γιατί. Η μεταφορά του event εκεί επιτρέπει στον consumer να το επιβεβαιώσει και να συνεχίσει με το επόμενο. Τίποτα δεν χάνεται· απλώς μπαίνει στην άκρη.
Διόρθωση και replay
Κάποιος κοιτάζει το dead-letter topic, διορθώνει την αιτία (δημιουργεί τον πελάτη C-1042 στο ERP, διορθώνει το
mapping) και κάνει replay του event προς τον αρχικό consumer. Επειδή οι consumers είναι idempotent, το replay ενός
event που στην πράξη είχε επεξεργαστεί μερικώς είναι ασφαλές.
orders.created ──► consumer τιμολόγησης ──ok──► ERP
│
αποτυγχάνει N φορές / μόνιμο σφάλμα
▼
orders.created.invoicing.dlt ──► ειδοποίηση ──► διόρθωση ──► replay ──► consumer τιμολόγησης
Προσέξτε ότι το DLT είναι ανά consumer. Αν η τιμολόγηση απέτυχε αλλά η αποθήκη πέτυχε, replay χρειάζεται μόνο η τιμολόγηση.
Υλοποίηση στο Boomi
Το Boomi Event Streams είναι χτισμένο πάνω στο Apache Pulsar, που υποστηρίζει εγγενώς redelivery και dead-letter topics σε επίπεδο subscription. Ανάλογα με την έκδοση, το listen operation του Boomi Event Streams connector μπορεί να προσφέρει απευθείας ρυθμίσεις για redelivery και dead-letter topic· ελέγξτε την τρέχουσα τεκμηρίωση του connector για το τι είναι διαθέσιμο και πώς ονομάζεται. Η προσέγγιση παρακάτω υλοποιεί το pattern ρητά μέσα στο consumer process, οπότε δουλεύει σε κάθε περίπτωση και σας δίνει πλήρη έλεγχο στην ταξινόμηση των σφαλμάτων και στις πληροφορίες που κρατάτε για κάθε αποτυχημένο event.
Βήμα 1: Δημιουργήστε το dead-letter topic
Στο Event Streams, στο ίδιο environment με το orders.created, δημιουργήστε ένα topic για τις αποτυχίες του consumer
τιμολόγησης, π.χ. orders.created.invoicing.dlt, και ένα subscription σε αυτό με όνομα replay. Το ίδιο για κάθε
consumer που χρειάζεται. Μια σύμβαση ονομάτων (<topic>.<consumer>.dlt) κάνει προφανές από πού ήρθε ένα αποτυχημένο
event.
Βήμα 2: Τυλίξτε τη δουλειά σε Try/Catch
Στο consumer process της τιμολόγησης (από το Publish μία φορά, πολλοί consumers: pub/sub με το Boomi Event Streams), τοποθετήστε ένα Try/Catch shape αμέσως μετά το Start shape, ώστε ό,τι μιλά με το ERP να βρίσκεται στη διαδρομή Try.
- Ρυθμίστε το Try/Catch να πιάνει σφάλματα ανά document, ώστε ένα event που αποτυγχάνει να μη ρίχνει τα υπόλοιπα της ίδιας εκτέλεσης.
- Χρησιμοποιήστε το retry count του Try/Catch για τα προσωρινά σφάλματα: το shape μπορεί να ξανατρέξει τη διαδρομή Try μερικές φορές πριν στείλει το document στη διαδρομή Catch. Κρατήστε τον αριθμό μικρό.
Για έλεγχο στις καθυστερήσεις ανάμεσα στις προσπάθειες, κάποιες ομάδες υλοποιούν τα retries με έναν μετρητή σε dynamic document property και επαναδημοσίευση σε ξεχωριστό retry topic. Ξεκινήστε απλά και προσθέστε το μόνο αν το χρειαστείτε.
Βήμα 3: Ταξινόμηση στη διαδρομή Catch
Στη διαδρομή Catch, το μήνυμα σφάλματος είναι διαθέσιμο μέσω της ιδιότητας try/catch message του document. Με ένα Decision ή Route shape ξεχωρίστε τα γνωστά μόνιμα σφάλματα (ο πελάτης δεν βρέθηκε, σφάλματα επικύρωσης από το ERP) από όλα τα άλλα. Και τα δύο καταλήγουν στο dead-letter topic, αλλά ίσως θέλετε διαφορετική ειδοποίηση: ένα μόνιμο σφάλμα δεδομένων πηγαίνει στο back office των πωλήσεων, ένα επίμονο τεχνικό σφάλμα στο IT.
Πριν από αυτό, προσθέστε στη διαδρομή Try ελέγχους για τα μόνιμα σφάλματα που μπορείτε να προβλέψετε, όπως «ο πελάτης υπάρχει στο ERP» ή «όλοι οι κωδικοί ειδών είναι γνωστοί». Μια έγκαιρη αποτυχία με σαφές μήνυμα είναι πολύ καλύτερη από ένα δυσνόητο σφάλμα του ERP.
Βήμα 4: Δημοσίευση στο dead-letter topic
Πάντα στη διαδρομή Catch:
- Με ένα Map ή Message shape τυλίξτε το αρχικό event με τα στοιχεία της αποτυχίας:
{
"failedAt": "2026-10-23T09:14:09Z",
"consumer": "invoicing",
"sourceTopic": "orders.created",
"errorType": "permanent",
"errorMessage": "Customer C-1042 not found in ERP",
"attempts": 1,
"event": { "eventId": "7f1c2e9a-4b1d-4c55-9a51-2d1f0b7c9e10", "type": "order.created", "orderId": "58213", "customerId": "C-1042" }
}
- Στείλτε το με ένα shape του Boomi Event Streams connector με operation Produce στο
orders.created.invoicing.dlt. - Τερματίστε κανονικά τη διαδρομή Catch, ώστε το αρχικό event να επιβεβαιωθεί και ο consumer να προχωρήσει. Βεβαιωθείτε πρώτα ότι η δημοσίευση στο DLT πέτυχε· αν αποτύχει, αφήστε το process να βγάλει σφάλμα ώστε το αρχικό event να ξαναπαραδοθεί αντί να χαθεί.
Βήμα 5: Ειδοποίηση και έλεγχος
- Προσθέστε ειδοποίηση στη διαδρομή Catch (π.χ. email ή μήνυμα σε κανάλι Teams/Slack μέσω του connector τους) με τον αριθμό παραγγελίας, τον πελάτη και το μήνυμα σφάλματος, όχι απλώς «το process απέτυχε».
- Παρακολουθείτε το backlog του subscription
replayτου DLT στο Event Streams. Ένα μη κενό DLT σημαίνει δουλειά για κάποιον. - Χρησιμοποιήστε το Process Reporting για να δείτε τα documents της αποτυχημένης εκτέλεσης όταν το μήνυμα μόνο του δεν αρκεί.
Βήμα 6: Replay μετά τη διόρθωση
Φτιάξτε ένα μικρό replay process:
- Ξεκινά με τον Event Streams connector να καταναλώνει από το
orders.created.invoicing.dltστο subscriptionreplay. Πολλές ομάδες κρατούν αυτόν τον listener σταματημένο και τον ξεκινούν μόνο όταν θέλουν replay, ή τρέχουν το process χειροκίνητα, ώστε να μη γίνει replay πριν διορθωθεί η αιτία. - Εξάγετε το αρχικό
eventαπό το «περιτύλιγμα» με ένα Map shape. - Επιστρέψτε το στη λογική της τιμολόγησης. Η πιο καθαρή επιλογή είναι να το δημοσιεύσετε σε ένα ειδικό retry topic
που ακούει μόνο ο consumer τιμολόγησης, π.χ.
orders.created.invoicing.retry. Μια επαναδημοσίευση στο ίδιο τοorders.createdθα έστελνε το event ξανά στην αποθήκη και στο CRM· η idempotency σάς προστατεύει, αλλά είναι θόρυβος.
Επειδή ο consumer τιμολόγησης ελέγχει αν η web παραγγελία υπάρχει ήδη πριν τη δημιουργήσει, το replay ενός event που είχε επεξεργαστεί μερικώς δεν δημιουργεί διπλό τιμολόγιο.
Πριν βγείτε σε παραγωγή
- Δοκιμάστε με πραγματικό poison message. Στείλτε παραγγελία για πελάτη που δεν υπάρχει στο ERP και ακολουθήστε τη μέχρι το DLT, την ειδοποίηση και πίσω μέσω του replay.
- Ορίστε συνειδητά το retention των DLTs. Τα events σε ένα DLT πρέπει να μένουν αρκετά ώστε κάποιος να τα διορθώσει, ακόμη και μετά από ένα τριήμερο.
- Δώστε στο DLT υπεύθυνο. Ένα dead-letter topic που δεν κοιτάζει κανείς είναι απλώς ένας πιο αργός τρόπος να χάνετε παραγγελίες.
- Όχι dead-letter σε πλήρη διακοπή. Αν το ERP είναι εκτός, κάθε event θα αποτύχει. Σκεφτείτε να σταματήσετε τον listener, ώστε τα events να περιμένουν στο κύριο subscription αντί να πλημμυρίσουν το DLT.
- Καταγράφετε παντού το event ID, ώστε να ακολουθείτε μία παραγγελία από producer, consumer, DLT και replay.
Για τα γενικά patterns χειρισμού σφαλμάτων και retries σε integrations χωρίς events, δείτε το Χειρισμός σφαλμάτων και retries στο Boomi.
Σύνοψη
Τα poison messages είναι αναπόφευκτα· οι χαμένες ή κολλημένες παραγγελίες όχι. Ταξινομήστε τα σφάλματα, κάντε λίγα retries στα προσωρινά, βάλτε στην άκρη τα μόνιμα σε dead-letter topic ανά consumer με σαφή εξήγηση, και κάντε replay μόλις διορθωθεί η αιτία. Στο Boomi, το Event Streams κρατά τα topics, και το Try/Catch μαζί με τον Event Streams connector υλοποιούν τη ροή. Για τις έννοιες πίσω από αυτό, δείτε τον οδηγό Event-driven integration: τι είναι και πότε το χρειάζεστε.