Dead Letter Channel
Quand un message ne peut pas être traité — syntaxe cassée, format inconnu, validation métier échouée, retry épuisés — il doit aller quelque part. Le Dead Letter Channel est ce « quelque part » canonique. Sans lui, les messages se perdent en silence et les incidents apparaissent en J+30 quand le partenaire appelle.
Problème
Dans un pipeline EDI, plusieurs choses peuvent rendre un message intraitable : l'enveloppe est corrompue et le parser EDIFACT refuse, le partenaire a envoyé un type de message inattendu, la validation métier (TVA non reconnue, GLN inconnu) bloque l'intégration, le nombre de retries autorisés est épuisé. Sans un canal explicite pour ces cas, deux pathologies : (a) le message est jeté silencieusement et l'incident ne sort qu'à J+30, ou (b) le pipeline boucle indéfiniment sur le même message et bloque tous les suivants.
Forces
- Garantie de non-perte. Un message reçu doit avoir un destin observable, même si ce destin est « à examiner par un humain ». Le silence est inadmissible.
- Isolation du pipeline. Un message empoisonné (poison message) ne doit pas bloquer le traitement des suivants.
- Contexte d'échec. Pour qu'un opérateur puisse diagnostiquer, le message DLC doit porter la raison, le stade d'échec, l'horodatage, et le payload original.
- Replay possible. Une fois le problème corrigé (référentiel mis à jour, parser patché), il doit être facile de rejouer le message DLC dans le pipeline normal.
Solution
EIP §119 (Hohpe & Woolf, 2003) modélise le Dead Letter Channel comme un canal spécial, distinct du pipeline normal, où les messages inacceptables sont déposés avec un enrichissement de métadonnées d'erreur. Chaque consommateur du pipeline doit avoir une porte DLC : parser, validateur, mapper, intégrateur. Le DLC est consommé par un système d'opération (console, alertes, dashboards), pas par le pipeline métier.
ORDERS ┌──────────────┐
──────────────────▶│ Translator │ ──▶ canonical
└──────┬───────┘
│ erreur de parse
▼
┌──────────────┐
│ DLC │
│ /dlq/orders │
└──────┬───────┘
│
▼
opérateur humain
(replay / discard / fix) Topologie
Trois variantes :
- Single DLC. Une seule queue
dlq.globalpour tout le pipeline. Simple, mais difficile à monitorer par type d'erreur. - DLC par stade. Une queue par étape :
dlq.parse,dlq.validate,dlq.integrate. Permet à chaque équipe de monitorer son domaine. - DLC par partenaire. Une queue par partenaire EDI — utile en exploitation pour escalader vers le bon interlocuteur en cas de pic d'erreurs sur un partenaire donné.
Souvent, on combine les trois : une queue par partenaire avec un sous-routage par stade, et un dashboard global qui agrège.
Implémentation EDI
Cas typiques d'envoi en DLC :
- Syntaxe cassée. Un ORDERS avec UNH manquant, ISA avec champ tronqué, XML invalide. Le parser refuse → DLC immédiat, et idéalement un CONTRL négatif (action 7) émis vers l'émetteur.
- Format inconnu. Le Normalizer n'arrive pas à détecter le format. DLC + alerte.
- Identifiant non résolu. Un GLN qui ne figure pas dans la base partenaires. DLC avec hint « ajouter le partenaire ou rejeter ».
- Validation métier échouée. TVA invalide, cohérence quantité/prix cassée, devise non supportée. DLC avec détail des règles violées.
- Retry épuisés. Le pipeline a tenté N fois d'intégrer dans l'ERP ; l'ERP refuse toujours. DLC plutôt que blocage infini.
Métadonnées indispensables
Un message en DLC doit porter au minimum :
- originalChannel — d'où vient le message.
- failedAt — horodatage de l'échec.
- attemptCount — combien de fois on a tenté.
- lastError — type, code, message lisible, stack éventuelle.
- metadata transport — émetteur, destinataire, référence d'interchange, taille, hash.
- payloadRef — pointeur vers le payload original stocké en archive (cf. pattern Claim Check).
{
"dlcVersion": "1",
"originalChannel": "orders.in",
"errorChannel": "orders.dlq",
"failedAt": "2026-05-14T15:45:33Z",
"attemptCount": 5,
"lastError": {
"stage": "parser",
"type": "EDIFACT_SYNTAX",
"code": "UNH-MISSING",
"message": "UNH header not found after UNB",
"stack": "..."
},
"metadata": {
"transport": "AS2",
"from": "ZZZSENDER",
"to": "ZZZRECEIVER",
"interchangeRef": "ORD202605140001",
"size": 2487,
"sha256": "9a4b1c2..."
},
"payloadRef": "s3://ediverse-archive/dlq/2026/05/14/ord-202605140001.edi"
} Anti-patterns
- Log + silence. Logger l'erreur et abandonner le message n'est pas un Dead Letter Channel — c'est une perte. Le DLC doit être inspectable et rejouable.
- Re-tentative infinie. Sans plafond de retry, un poison message bloque le pipeline indéfiniment. Toujours basculer en DLC après N tentatives.
- DLC sans monitoring. Une queue DLC qu'on ne regarde jamais ne sert à rien. Toujours alerter sur taille > 0 pendant une fenêtre.
- Pas de mécanisme de replay. Si on doit reconstituer chaque message à la main pour le rejouer, l'opérateur passera la journée à recopier des UNB. Fournir un outil de replay qui lit le DLC et republie vers la queue d'origine.
- DLC partagé entre prod et test. Mélanger les environnements en DLC est une recette de confusion. Toujours cloisonner.
Patterns liés
- Retry & backoff — la politique qui décide quand basculer en DLC.
- Flux d'exception — la matrice d'escalade qui consomme le DLC.
- Claim Check — pour stocker le payload original sans charger la queue.
Sources
- Hohpe G., Woolf B. — Enterprise Integration Patterns, pattern Dead Letter Channel (§119). enterpriseintegrationpatterns.com — Dead Letter Channel
- AWS SQS — Dead-letter queues. Documentation officielle de la mise en œuvre dans SQS. docs.aws.amazon.com — SQS DLQ
- RabbitMQ — Dead Letter Exchanges. Le mécanisme AMQP standard de bascule en DLQ. rabbitmq.com — DLX
- Bugayenko Y. — Elegant Objects, 2017. Sur l'importance de transformer toute défaillance en signal explicite plutôt qu'en silence — fondement philosophique du DLC.