Leçon 17 / 20

Assembler le flux de facturation asynchrone

25 min Node.js — production, files d’attente et sécurité Gratuit

Objectif : Relier l’API de commandes, la file de tâches et le worker dans un parcours complet, tout en propageant l’identifiant de corrélation.

Une API peut enregistrer une commande et répondre correctement sans que la facture soit réellement produite. Pour exploiter le service, vous devez relier la route, le producteur de tâches et le worker, puis pouvoir suivre une même demande dans leurs journaux.

Dans les leçons précédentes, vous avez défini le contrat de la tâche, la publication après persistance et le traitement résistant aux échecs. Ici, vous les assemblez : l’API publie une tâche après l’enregistrement de la commande, et un processus worker la consomme avec le service de facturation.

Définir le point de raccordement

La file est une dépendance partagée, mais l’API et le worker ne sont pas le même processus. L’API reçoit un producteur capable de publier une tâche ; le worker reçoit un consommateur capable de remettre une tâche au gestionnaire. Les deux adaptateurs doivent respecter le contrat déjà défini pour le message de facture, notamment son identifiant de commande et sa version.

Le code suivant présente un point de composition dans src/app.js. Il reçoit les éléments déjà construits par l’application — route, producteur, consommateur, service métier et journal — au lieu de créer une connexion à la base ou à la file dans le module. La route reçoit également les middlewares d’accès et de limitation, dans l’ordre établi précédemment.

src/app.jsTexte
function creerApplication({
  express,
  creerRouteCommandes,
  depotCommandes,
  producteurFactures,
  authentifier,
  limiterApi,
  journal
}) {
  const app = express();

  app.use(express.json());
  app.use(creerRouteCommandes({
    depot: depotCommandes,
    producteur: producteurFactures,
    authentifier,
    limiterApi,
    journal
  }));

  app.use((erreur, req, res, next) => {
    journal.erreur({
      evenement: 'requete_echouee',
      correlationId: req.correlationId,
      erreur: erreur.message
    });

    if (res.headersSent) {
      return next(erreur);
    }

    res.status(500).json({ erreur: 'Erreur interne' });
  });

  return app;
}

function demarrerWorker({
  consommateurFactures,
  serviceFactures,
  journal
}) {
  return consommateurFactures.consommer(async (tache) => {
    journal.info({
      evenement: 'facture_debut',
      correlationId: tache.correlationId,
      commandeId: tache.commandeId
    });

    await serviceFactures.generer(tache.commandeId);

    journal.info({
      evenement: 'facture_terminee',
      correlationId: tache.correlationId,
      commandeId: tache.commandeId
    });
  });
}

module.exports = { creerApplication, demarrerWorker };

Ce module fixe le raccordement, mais ne crée volontairement ni serveur de file ni connexion de production : leurs constructeurs dépendent de votre infrastructure. Lors du démarrage, construisez les adaptateurs avec la configuration déjà validée, puis fournissez-les à ces fonctions. L’API passe le producteur à la route ; le processus worker passe le consommateur et le service métier à demarrerWorker.

Suivre une facture de bout en bout

L’identifiant de corrélation doit accompagner la requête jusqu’au message de tâche. Dans votre route, transmettez-le au producteur avec les données métier déjà prévues par le contrat. Le producteur ne doit pas le confondre avec l’identifiant de commande : le premier sert au suivi technique, le second identifie l’opération métier.

Publication dans la route de commandesTexte
await producteur.publier({
  version: 1,
  commandeId: commande.id,
  correlationId: req.correlationId
});

Cet extrait indique le raccordement attendu dans la route existante ; ce n’est pas un fichier autonome à exécuter isolément. Gardez dans cette route l’enregistrement préalable et la gestion d’erreur déjà établis. L’adaptateur de file doit accepter ce message et le consommateur doit le remettre au gestionnaire avec les mêmes propriétés, sans en reconstruire l’identifiant de corrélation.

Séparer les processus et leur configuration

Le serveur web et le worker peuvent être déployés séparément, même s’ils utilisent les mêmes composants de file et de données. Le serveur web démarre l’application Express ; le worker démarre le consommateur. Ne lancez pas les deux rôles par effet de bord lors de l’importation de src/app.js : le module doit rester testable et le processus doit choisir explicitement son rôle.

Les paramètres propres au worker — par exemple la concurrence et les paramètres de connexion — proviennent de la configuration validée selon l’environnement, conformément à la leçon de configuration. Injectez cette configuration aux constructeurs d’adaptateurs et au démarrage du consommateur ; ne lisez pas directement des variables d’environnement dans le code métier et n’inscrivez aucune valeur secrète dans le dépôt.

Vérifier le parcours assemblé

En exploitation, une commande acceptée doit d’abord être persistée, puis sa tâche publiée ; le worker doit ensuite appeler le service de facture. Suivez ces étapes avec le même identifiant de corrélation dans les journaux de l’API et du worker. Si la publication échoue, la route doit conserver le comportement d’erreur déjà défini, plutôt que de répondre comme si la file avait accepté la tâche.

À retenir

  • Injectez le producteur dans la route et le consommateur dans le worker ; gardez ces rôles séparés.
  • Transmettez au worker le message de tâche conforme au contrat, avec l’identifiant de commande et l’identifiant de corrélation.
  • Construisez les adaptateurs avec la configuration validée de l’environnement, sans valeurs sensibles en dur.
  • Vérifiez le parcours complet dans les journaux, de la publication à la fin du traitement.

La prochaine leçon ajoutera l’export protégé en streaming en composant les protections d’accès avec le pipeline de transfert.

Envie d'aller plus loin ?

Les cours Enovatic sont gratuits et le resteront. Si vous cherchez un accompagnement encadré, nos formations professionnelles sont animées par les mêmes formateurs.