ITSkillsCenter
Business Digital

Construire une chaîne événementielle PME avec NATS JetStream — tutoriel 2026

14 min de lecture

📍 Article principal : Redpanda vs NATS vs RabbitMQ pour PME 2026. Ce tutoriel construit une chaîne événementielle complète sur NATS JetStream, idéale pour les TPE et PME qui privilégient la simplicité et la légèreté.

NATS est l’antithèse de Kafka — petit binaire de 15 Mo, démarrage en deux secondes, configuration de quelques lignes YAML, empreinte mémoire de 256 Mo en single-node. Et pourtant, avec son module JetStream, NATS gère la persistance, les groupes de consommateurs, le replay et les politiques de rétention exactement comme Kafka, avec des performances qui tiennent jusqu’à 80 000 messages/seconde sur un VPS modeste. Pour une PME ouest-africaine qui veut le streaming d’événements sans la complexité opérationnelle, NATS JetStream est imbattable.

Ce tutoriel pose une chaîne événementielle complète : déploiement NATS sur Coolify, organisation en streams par domaine métier, comptes multi-tenants pour cloisonner les flux, gestion fine des retry et des dead letter queues, supervision via Prometheus + Grafana. À la fin, la PME dispose d’une infrastructure streaming fiable, sécurisée et observable, opérationnelle en moins d’une journée.

Prérequis

  • VPS avec Coolify installé (Hetzner CX22 suffit : 2 vCPU, 4 Go RAM, 40 Go SSD)
  • Sous-domaine nats.masociete.sn avec DNS A configuré
  • Notions Linux et configuration YAML
  • Niveau : intermédiaire
  • Temps estimé : 2 à 3 heures

Étape 1 — Comprendre l’architecture NATS

Avant de plonger dans le déploiement, comprendre les concepts clés. Un subject dans NATS correspond grossièrement à un topic dans Kafka, mais avec une syntaxe hiérarchique séparée par des points qui permet le filtrage par wildcard. Un client peut s’abonner à commerce.*.created pour recevoir tous les événements de création toutes entités confondues, ou à commerce.order.> pour recevoir tous les événements liés aux commandes (le > est un wildcard de fin).

NATS Core est un broker pub-sub sans persistance, où un message non consommé immédiatement est perdu. JetStream ajoute une couche de persistance via le concept de stream : un stream capture les messages publiés sur un ensemble de subjects et les conserve sur disque selon une politique configurable. Les consumers sont attachés aux streams et lisent les messages avec des stratégies (push, pull, group) flexibles.

Cette séparation Core/JetStream donne une flexibilité unique : pour les notifications éphémères (ping live, statut en ligne), utiliser NATS Core sans persistance ; pour les événements métier critiques, utiliser JetStream avec persistance disque. Sur le même serveur, sur les mêmes connexions clients, sans surcoût opérationnel.

Étape 2 — Déployer NATS via Coolify

NATS dispose d’une image Docker officielle minimaliste. Créer un nouveau projet Coolify avec ce compose qui active JetStream, monitoring HTTP, et persistance des données.

services:
  nats:
    image: nats:2.11-alpine
    container_name: nats
    command:
      - "-js"
      - "-sd=/data"
      - "-m=8222"
      - "--http_port=8222"
      - "--name=nats-prod"
      - "--cluster_name=masociete"
      - "--config=/etc/nats/nats-server.conf"
    volumes:
      - nats_data:/data
      - ./nats-server.conf:/etc/nats/nats-server.conf
    ports:
      - "4222:4222"
      - "8222:8222"
      - "6222:6222"
volumes:
  nats_data:

Le fichier nats-server.conf contient la configuration applicative : limites JetStream, authentification, ACL. Démarrer simple avec une configuration de base, puis durcir progressivement.

jetstream {
  store_dir: /data
  max_memory_store: 1GB
  max_file_store: 50GB
}

http_port: 8222

accounts {
  SYS: { users: [{user: sys, password: $SYS_PASS}] }
  COMMERCE: { jetstream: enabled, users: [{user: commerce, password: $COM_PASS}] }
  LOGISTICS: { jetstream: enabled, users: [{user: logistics, password: $LOG_PASS}] }
}
system_account: SYS

Cette configuration crée trois comptes isolés : SYS pour l’administration, COMMERCE pour l’application e-commerce, LOGISTICS pour l’application logistique. Chaque compte a son propre namespace JetStream — les messages publiés dans COMMERCE ne sont pas visibles depuis LOGISTICS. Cette isolation native est l’un des atouts majeurs de NATS pour une plateforme multi-application.

Déployer le projet via Coolify, configurer Caddy pour exposer le port HTTP 8222 (interface monitoring) en HTTPS via le sous-domaine. Au bout de quelques minutes, l’instance NATS est opérationnelle. Vérifier la santé :

curl https://nats.masociete.sn/varz | jq
# Doit afficher l'état du serveur
curl https://nats.masociete.sn/jsz | jq
# État de JetStream

Étape 3 — Créer les streams par domaine métier

Installer le client CLI nats qui sert à administrer les streams et tester la publication-consommation. Sur Linux/Mac, l’installation se fait via Homebrew, Snap ou téléchargement binaire direct depuis GitHub releases.

curl -sSL https://nats.io/install.sh | bash
nats context save commerce \
  --server tls://nats.masociete.sn:4222 \
  --user commerce --password <mdp>
nats context select commerce

# Créer le stream commerce
nats stream add COMMERCE_EVENTS \
  --subjects "commerce.>" \
  --storage file \
  --retention limits \
  --max-age 30d \
  --max-bytes 5GB \
  --discard old \
  --replicas 1

Ce stream capture tous les événements publiés sur commerce.> (commerce.order.created, commerce.product.updated, etc.), les conserve 30 jours ou jusqu’à 5 Go, supprime les plus anciens quand la limite est atteinte. Créer de la même manière les streams LOGISTICS_EVENTS et BILLING_EVENTS pour cloisonner les domaines.

La séparation par domaine métier facilite la gouvernance : chaque équipe gère son stream, applique sa politique de rétention, et accorde des permissions à ses consommateurs. Les inter-dépendances entre domaines passent par des publications croisées explicites — par exemple, le module logistique consomme commerce.order.created pour préparer la livraison.

Étape 4 — Producteur et consommateur Python

Le client Python officiel nats-py avec son extension JetStream couvre tous les besoins d’un client production. Installer la dépendance et écrire un premier producteur asynchrone.

pip install nats-py

# producer.py
import asyncio, json, uuid
import nats

async def main():
  nc = await nats.connect(
    "tls://nats.masociete.sn:4222",
    user="commerce", password="<mdp>")
  js = nc.jetstream()
  event = {
    "event_id": str(uuid.uuid4()),
    "order_id": "CMD-2026-04-29-001",
    "amount_xof": 25000,
  }
  ack = await js.publish(
    "commerce.order.created.v1",
    json.dumps(event).encode(),
    headers={"Idempotency-Key": event["event_id"]})
  print(f"Stored at sequence {ack.seq}")
  await nc.drain()

asyncio.run(main())

Le header Idempotency-Key active la déduplication côté JetStream — si le producteur retente la publication avec le même identifiant dans une fenêtre de 2 minutes, le message n’est stocké qu’une seule fois. Cette garantie élimine les doublons sans complexité côté application.

Pour le consommateur, créer un consumer durable qui survit aux redémarrages et reprend là où il s’était arrêté.

# consumer.py
async def main():
  nc = await nats.connect("tls://nats.masociete.sn:4222",
    user="logistics", password="<mdp>")
  js = nc.jetstream()
  sub = await js.pull_subscribe(
    "commerce.order.created.>",
    durable="logistics-prepare-delivery",
    stream="COMMERCE_EVENTS")
  while True:
    msgs = await sub.fetch(batch=10, timeout=5)
    for msg in msgs:
      event = json.loads(msg.data)
      try:
        prepare_delivery(event)
        await msg.ack()
      except Exception as e:
        await msg.nak(delay=60)
asyncio.run(main())

Le consumer durable logistics-prepare-delivery garde la trace de l’offset traité dans NATS. En cas de crash, le redémarrage reprend à l’événement non encore acquitté. Le mécanisme NAK avec délai permet de retenter un message en cas d’erreur transitoire — par exemple si l’API logistique est temporairement indisponible.

Étape 5 — Dead letter queue et retry

Un message qui échoue de manière persistante (par exemple une commande malformée que personne ne peut traiter) ne doit pas bloquer le flux. La pratique standard : après 3 échecs successifs, déplacer le message dans une dead letter queue (DLQ) où un humain pourra l’analyser. JetStream supporte ce pattern via les paramètres max_deliver et un stream DLQ dédié.

nats stream add COMMERCE_DLQ \
  --subjects "commerce.dlq.>" \
  --storage file --retention limits --max-age 365d

nats consumer add COMMERCE_EVENTS dlq-router \
  --filter "commerce.order.created.>" \
  --max-deliver 3 \
  --backoff "30s,2m,10m"

Le consumer applique un backoff exponentiel entre les retry. Au troisième échec, le message est automatiquement transféré dans la DLQ avec un wrapper qui contient l’erreur d’origine, le nombre de tentatives, le timestamp du dernier échec. Un dashboard Grafana qui surveille la taille de la DLQ alerte l’admin dès qu’un nombre significatif de messages s’y accumule — signal clair d’un bug applicatif à corriger.

Étape 6 — Supervision et alerting

NATS expose ses métriques via l’endpoint HTTP /varz et un exporter Prometheus officiel. Déployer prometheus-nats-exporter en sidecar du conteneur NATS et le configurer pour scrapper les endpoints monitoring. Le dashboard Grafana officiel NATS (ID 18378) visualise instantanément le débit, le nombre de connexions, l’utilisation mémoire, l’état de chaque stream JetStream.

Configurer trois alertes essentielles. Première : stream avec consommateur en lag de plus de 5 minutes. Deuxième : nombre de messages dans la DLQ supérieur à 10. Troisième : utilisation disque JetStream supérieure à 70 %. Ces alertes anticipent les incidents avant qu’ils n’impactent les utilisateurs finaux.

Cluster NATS multi-nœuds pour la résilience

Un seul nœud NATS suffit pour des charges modérées et un objectif RTO de quelques minutes. Pour une véritable haute disponibilité, déployer un cluster de trois nœuds répartis sur trois VPS distincts. NATS gère nativement le clustering avec un protocole de gossip qui propage automatiquement les nouveaux nœuds sans configuration centralisée. La réplication JetStream avec replication factor 3 garantit qu’un nœud peut tomber sans perte de données ni interruption de service pour les producteurs et consommateurs.

Concrètement, sur trois VPS Hetzner CX22 distincts, chaque nœud référence les deux autres via la directive cluster.routes. Les streams créés avec --replicas 3 stockent automatiquement chaque message sur les trois nœuds. Le coût total de cette architecture résiliente tourne autour de 15 €/mois pour les trois VPS, soit 180 €/an pour une infrastructure broker capable d’absorber une panne datacenter complète. Aucun cloud managé ne tient ce niveau de prix-performance.

Migration vers NATS depuis un broker existant

Pour les PME qui veulent migrer depuis RabbitMQ ou Kafka vers NATS, plusieurs stratégies coexistent. La plus simple consiste à déployer NATS en parallèle, écrire des bridges qui relaient les messages depuis l’ancien broker vers NATS, basculer progressivement les consommateurs sur NATS, basculer enfin les producteurs, décommissionner l’ancien broker. La fenêtre de migration tient en deux à quatre semaines pour une PME standard, sans coupure de service utilisateur.

Le bridging se fait avec un petit programme Go ou Python qui s’abonne au broker source et republie sur NATS. Pour des volumes faibles, c’est suffisant. Pour des volumes massifs, NATS dispose d’un connecteur officiel nats-kafka-bridge qui simplifie la mise en œuvre et garantit la cohérence des offsets. La documentation officielle NATS détaille chaque scénario de migration avec les commandes exactes à exécuter.

Patterns NATS spécifiques : KV Store et Object Store

NATS JetStream fournit deux fonctionnalités annexes très utiles pour une PME : le KV Store et l’Object Store. Le KV Store transforme NATS en base clé-valeur distribuée avec versioning et watchers : idéal pour stocker la configuration applicative, les feature flags, les sessions utilisateur. Une mise à jour d’une clé déclenche automatiquement une notification chez tous les watchers — pratique pour propager une configuration sans redémarrage applicatif.

L’Object Store permet de stocker et distribuer des fichiers binaires (images, PDF, audios) via les mêmes mécanismes JetStream. Pour une PME qui a besoin de partager des PDF de factures entre services, l’Object Store évite l’introduction d’un MinIO séparé. Les capacités sont plus limitées qu’un vrai stockage objet (taille max de quelques Go), mais suffisantes pour la majorité des cas d’usage internes. Cette polyvalence — broker, KV, Object — fait de NATS une vraie boîte à outils pour la communication inter-services.

Tester en local avant la production

Pour valider une configuration NATS avant le déploiement Coolify, tester localement avec Docker. Un simple docker run --rm -it -p 4222:4222 -p 8222:8222 nats:2.11-alpine -js lance une instance JetStream complète accessible sur localhost. Les développeurs peuvent itérer rapidement sur les schémas de subjects, les politiques de rétention, les configurations de consumers, sans risquer de polluer la production.

Mettre en place une suite de tests d’intégration dans la CI Coolify qui démarre une instance NATS éphémère, exécute un scénario complet (publication, consommation, ack, retry, DLQ) et valide les invariants attendus. Cette couverture automatisée détecte les régressions avant la mise en production et donne confiance lors des mises à jour de version. Les développeurs Python utilisent pytest avec un fixture qui démarre NATS via testcontainers ; les développeurs Go utilisent go test avec un setup similaire. Le coût en temps de CI reste sous 30 secondes par test grâce au démarrage rapide de NATS.

Erreurs fréquentes

ErreurCauseSolution
Messages non persistésJetStream non activé (-js manquant)Vérifier le command line ou la conf, voir jetstream dans /varz
Consumer durable disparaît au redémarrageStockage in-memory au lieu de fileConfigurer --storage file sur le stream
Auth refusée malgré bons identifiantsCompte mal référencé ou ACL stricteVérifier le compte dans la conf, tester avec nats account info
Disque saturé après quelques semainesPas de max_age ou max_bytesConfigurer les limites de rétention dès la création du stream

Adaptation au contexte ouest-africain

NATS brille particulièrement quand la PME a des consommateurs en zone à connectivité instable. Le client NATS gère nativement les reconnexions automatiques, le buffering local pendant les coupures et le rattrapage à la reprise. Une application mobile coursier qui perd la 4G pendant 10 minutes ne perd aucun événement — elle resynchronise dès la reprise. Cette robustesse face aux conditions réseau africaines est un avantage souvent sous-estimé. Pour les déploiements multi-pays (Sénégal + Côte d’Ivoire par exemple), NATS supporte le clustering étendu — un cluster NATS peut s’étendre sur plusieurs régions avec une réplication asynchrone configurable, idéal pour rapprocher le broker des consommateurs et réduire la latence ressentie.

Pour finir, retenir que NATS récompense les équipes qui investissent dans la propreté opérationnelle. Bien nommer les subjects, bien cloisonner les comptes, bien dimensionner les rétentions, bien superviser les DLQ — chacune de ces disciplines simples préserve la lisibilité du système au fil des mois. Une PME qui démarre proprement avec NATS construit ainsi un socle événementiel robuste qui supporte des années de croissance et de complexité applicative croissante, sans jamais redevenir un goulot d’étranglement opérationnel.

L’écosystème NATS s’enrichit chaque trimestre : nouvelles intégrations cloud, connecteurs vers les bases de données populaires, améliorations de performance. Suivre la newsletter mensuelle de Synadia (l’éditeur principal de NATS) permet de rester à jour sur les fonctionnalités émergentes — par exemple la prise en charge native de WebSocket pour les clients navigateurs, qui ouvre des cas d’usage temps réel directement dans le frontend sans backend intermédiaire. Pour une PME ouest-africaine qui veut bâtir une plateforme événementielle moderne et durable, ce flux de nouveautés représente un avantage concurrentiel mesurable.

Pour aller plus loin

🔝 Retour à l’article principal : Redpanda vs NATS vs RabbitMQ pour PME 2026. Tutoriel précédent : déployer Redpanda sur Coolify.

Documentation officielle NATS : docs.nats.io, JetStream guide : docs.nats.io/nats-concepts/jetstream, communauté Slack très active sur natsio.slack.com. Le tutoriel suivant aborde RabbitMQ Streams pour comparer concrètement avec NATS sur les mêmes cas d’usage.

Pour pérenniser le déploiement, prévoir une revue mensuelle des comptes NATS : lister les utilisateurs actifs, vérifier les permissions, identifier les comptes inactifs depuis plus de 90 jours. Cette discipline prévient les fuites de credentials et maintient une posture sécuritaire saine. Documenter aussi les conventions de nommage des subjects et streams dans un wiki d’équipe — la cohérence vaut de l’or quand de nouveaux développeurs rejoignent l’équipe.

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité