Aller au contenu principal

Job queues / message broker

Une "job queue" est utile :

  • Pour faire un travail en asynchrone (et ne pas bloquer la requête courante qui est synchrone) ;
  • Répartir la charge : les tâches en attente peuvent être exécutées 1 par 1 ;
  • En cas d'échec on peut automatiquement rejouer le "job" jusqu'à temps que ça passe ;
Omission

Dans cette partie nous allons omettre le pattern d'event sourcing et de CQRS car nous estimons que les appliquer à tout son applicatif apporte une certaine complexité dans le développement. Étant dans un monolithe avec un seul stockage, et pouvant bénéficier de transactions SQL, vous devriez pouvoir passer outre (et donc nous ne parlerons dans la suite de "job queue", pas de "message broker").

Il ne faut pas essayer de tout garantir avec asynchronisme, vous risqueriez de complexifier votre outil (et donc sa phase de débogage). Voici quelques cas concrets :

  • Quand l'utilisateur envoie un formulaire, aucune raison de mettre cette action dans une file d'attente pour modifier la base de données, si quelque chose échoue il est acceptable que l'utilisateur reçoive une erreur serveur afin de retenter ;
  • Si vous devez faire une action métier sensible comme créer une transaction financière chez un partenaire, en faire un "job" permettra de vous garantir que si votre partenaire est hors service, la transaction sera quand même créée une fois que le partenaire sera de nouveau sur pieds ;
  • Si mes partenaires peuvent me notifier d'événements métiers indispensables à mon produit, il vaut mieux mettre le payload HTTP reçu (souvent du JSON) directement dans une "job queue" même si vous le traitez immédiatement. Cela permettra :
    1. Si vous avez une erreur temporaire, de pouvoir rejouer le webhook (très souvent les partenaires n'ont pas de logique de "retry" poussée donc il serait risqué de se reposer sur eux) ;
    2. Si jamais votre partenaire change de format de données dans son payload, on sait d'avance que cela ne passerait pas de votre côté car vous validez la donnée en entrée, il vaut mieux avoir le payload complet utilisé pour investiguer et savoir ce qu'il faut ajuster.

Nous préconisons d'utiliser la librairie pg-boss en lieu de place d'outils dédiés comme "Redis Pub/Sub", Kafka (…). Elle va savoir reproduire toute la logique des "job queues" en ayant quelques tables dans votre base de données. De plus :

  • Elle fait très bien le travail pour un usage normal ;
  • Cela vous évitera de devoir le maintenir un outil stateful supplémentaire ;
  • Cela vous évitera de devoir déboguer via plusieurs outils à la fois ;
  • Quand vous ferez un backup ou un "restore" de votre base de données, les événements seront synchronisés avec l'état global des données de votre produit.
Informations annexes
  • pg-boss sait gérer les cron jobs, donc plutôt que d'utiliser une fonctionnalité propre à votre provider (qui ne garantit souvent pas l'unicité de l'opération), vous pouvez vous en servir ;
  • Next.js ne permet pour l'instant pas de lancer directement des processus asynchrones (il faudrait modifier le serveur web mais on perdrait l'optimisation qu'ils ont fait). Notre approche est d'utiliser un endpoint /init qui sera appelé au lancement du serveur ;
  • À vous de choisir votre stratégie de rejeu en fonction de la criticité du job :
    • N'oubliez pas de spécifier un maximum de rejeux pour un job car certains ne passeront jamais et il serait dommage de flooder votre système ou vos partenaires (sans jamais traîter les jobs suivants, qui eux, peuvent peut-être passer) ;
    • Vous pouvez vous reposer sur Sentry pour être notifié d'un job qui est abandonné afin que vous puissiez investiguer et tenter de le rejouer manuellement.