Développement web

Multi-services web, queue, cron, workers : comment dockeriser sans se perdre ?

Jérémy Chomel Dawap
  • Publié le : 25 décembre 2025
  • Mis à jour le : 19 août 2026
  • Temps de lecture : 13 minutes
  1. Cartographier les processus avant les conteneurs
  2. Partager une image et varier les commandes
  3. Borner le contrat du service web
  4. Concevoir les workers pour la redélivrance
  5. Séparer planification et exécution des tâches
  6. Traiter la file comme un composant du produit
  7. Refuser les démarrages fondés sur l’ordre
  8. Définir une santé propre à chaque rôle
  9. Dimensionner sans laisser un service affamer les autres
  10. Déployer des versions compatibles avec le travail en attente
  11. Cas concret : commandes web, exports et factures
  12. Donner au support une chronologie commune
  13. Reconnaître le bon niveau de séparation
  14. Erreurs fréquentes d’une architecture multi-services
  15. Décider quels processus isoler
  16. Plan d’action sur six semaines
  17. Guides complémentaires pour tenir le run
  18. Conclusion : séparer l’exécution, conserver la causalité
Portrait de Jérémy Chomel

Le même dépôt Symfony sert une API, consomme deux files, génère des exports nocturnes et lance un rappel toutes les cinq minutes. Le problème apparaît lorsque l’équipe crée un conteneur pour chaque nom de commande, puis ne sait plus lequel déployer, superviser ou arrêter. Lorsqu’un export sature la base, le web ralentit et le scheduler republie le travail parce que son premier lancement n’a laissé aucun état lisible.

Le vrai enjeu est de séparer les contrats d’exécution sans fragmenter la compréhension du produit. Plusieurs processus peuvent partager image, code et configuration, tout en possédant commande, concurrence, ressources, santé et arrêt distincts. Le conteneur matérialise une responsabilité opérationnelle ; il ne doit pas devenir une copie technique créée pour chaque script.

Contre-intuitivement, moins de types de conteneurs rendent souvent le système plus isolable. Un web, une famille de workers par profil et un déclencheur de tâches suffisent lorsque les limites sont explicites. Multiplier les variantes avant d’avoir nommé files, idempotence et reprise transforme la topologie en documentation trompeuse.

Dans une application de développement web sur mesure, chaque processus doit raconter la même causalité métier. La démarche construit cette carte, qualifie le démarrage et les healthchecks, puis éprouve déploiement, panne et rollback avec le support avant d’augmenter le nombre de services.

Cartographier les processus avant les conteneurs

Partir des commandes et des effets

La carte recense serveur HTTP, consommateurs, tâches planifiées et opérations ponctuelles. Pour chacun, elle note entrée, sortie, dépendances, durée, effet externe, concurrence, état durable et propriétaire. Deux commandes qui utilisent le même code mais n’ont ni la même latence ni le même risque peuvent justifier des processus distincts.

Le web répond à une requête bornée. Un worker transforme une intention déjà enregistrée. Le planificateur décide quand soumettre un travail, pas comment exécuter toute sa logique. Une commande d’administration réalise une action contrôlée puis sort. Ces différences guident la topologie davantage que les noms de dossiers.

Établir la source de vérité

Le conteneur ne possède pas le statut métier. Base, file ou stockage externe conservent la vérité. Un redémarrage doit reprendre ou refuser proprement. Si l’état nécessaire ne survit que dans la mémoire du processus ou un fichier local, l’isolation en conteneur rend la perte plus fréquente sans la rendre plus visible.

Partager une image et varier les commandes

Web, workers et cron utilisent généralement le même code PHP, vendor et migrations. Une image commune réduit les divergences. Le déploiement change la commande, les variables non sensibles, les ressources et le nombre d’instances. Chaque rôle reste associé au même digest afin qu’un incident puisse être relié à une version unique.

Des images séparées deviennent pertinentes si la surface de sécurité, les extensions ou le cycle de publication divergent réellement. Un convertisseur média peut demander des binaires lourds absents du web. Cette exception possède un Dockerfile ou target, un scan et une maintenance. Elle ne justifie pas sept images presque identiques.

Garder l’entrée simple

L’entrypoint prépare les permissions strictement nécessaires puis exécute la commande reçue. Il ne choisit pas le rôle à partir d’une variable obscure, ne lance pas plusieurs daemons et n’applique pas automatiquement les migrations. Un processus principal clair permet aux signaux, logs et codes de sortie de garder leur sens.

Borner le contrat du service web

Le web accepte des requêtes courtes, applique authentification et règles, puis répond. Une opération longue est soit bornée par un timeout assumé, soit transformée en commande durable dont l’état devient visible. Envoyer un message ne permet pas d’annoncer que le travail est terminé ; l’API distingue reçu, en cours, réussi, refusé et résultat inconnu.

Le service web reste remplaçable. Sessions, uploads durables et verrous vivent hors de sa couche locale. La readiness vérifie sa capacité propre à servir, sans transformer chaque requête de santé en appel à toutes les dépendances. Si un partenaire est indisponible, un mode dégradé peut rester prêt tout en signalant la fonction concernée.

Protéger la base des rafales

Le nombre de processus web, le pool SQL et les timeouts sont cohérents. Ajouter des replicas ne multiplie pas arbitrairement les connexions. Une limite de concurrence et un contrôle de surcharge produisent une erreur maîtrisée plutôt qu’un effondrement de la base qui bloque aussi les workers.

Concevoir les workers pour la redélivrance

Un worker consomme un message, contrôle les préconditions, produit un effet puis acquitte. Il peut tomber après l’effet et avant l’acquittement ; le message revient. L’idempotence utilise une clé métier et une contrainte atomique lorsque l’effet ne peut pas être répété, plutôt qu’une simple vérification sujette à la concurrence.

La documentation officielle de Symfony Messenger décrit transports, retries et failure transports. Ces mécanismes ne classent pas l’erreur métier. Le handler distingue indisponibilité temporaire, donnée refusée, contrat incompatible et résultat externe inconnu, puis choisit retry, correction, rapprochement ou escalade.

Arrêter sans doubler l’effet

Le worker reçoit le signal, cesse de prendre du travail et termine dans une grace period supérieure à la durée normale. Les messages exceptionnellement longs doivent être découpés ou utiliser keepalive selon le transport. Tuer systématiquement après trente secondes peut déclencher deux traitements concurrents alors que le premier continue côté partenaire.

Séparer planification et exécution des tâches

Le scheduler détermine qu’un travail est dû et publie une commande avec une clé de période. Il ne conserve pas tout le traitement dans un cron monolithique. Si deux instances se chevauchent, la clé ou un verrou empêche la double soumission, tandis que la file garde visibilité, retry et reprise.

Une tâche ponctuelle de maintenance peut rester une commande qui s’exécute puis sort. Une tâche récurrente importante doit laisser heure prévue, heure lancée, périmètre, statut et résultat. Le support sait distinguer non-déclenchée, en attente, en cours et échouée sans lire seulement la crontab.

Choisir la sémantique du retard

Après une heure d’arrêt, faut-il rattraper douze occurrences ou une seule synthèse ? Le métier décide. Un rapport horaire et une purge quotidienne n’ont pas la même règle. Le planificateur encode cette politique, évitant une tempête de rattrapage au redémarrage.

Traiter la file comme un composant du produit

Chaque file correspond à une promesse et une priorité, pas nécessairement à une classe PHP. Séparer commandes urgentes, traitements lourds et notifications empêche un export de bloquer une révocation. Le routage reste versionné et les consommateurs déclarent les types compris.

Les métriques utiles sont âge du plus ancien, délai jusqu’au résultat, taux de retry, erreurs définitives et débit par catégorie. Une profondeur stable peut cacher un dossier vieux de deux jours. Le seuil est relié à une action : ajouter temporairement de la capacité, suspendre un producteur ou traiter une erreur de données.

Limiter l’orage de reprise

Quand une dépendance revient, tous les messages ne doivent pas repartir simultanément. Temporisation, jitter, concurrence et rate limit protègent base et partenaire. Les retries possèdent un budget compatible avec la promesse ; passé ce délai, le statut devient intervention requise au lieu de rester « en cours » indéfiniment.

Refuser les démarrages fondés sur l’ordre

Une dépendance démarrée n’est pas forcément prête. La documentation Docker sur l’ordre de démarrage Compose distingue notamment conditions et healthchecks. L’application doit malgré tout supporter reconnexion, car une base ou un broker peut tomber après le démarrage nominal.

Un script wait-for sans timeout masque parfois une panne et bloque le déploiement. Le processus valide sa configuration, tente ses dépendances selon une politique bornée puis expose un état clair. L’orchestrateur redémarre seulement les erreurs qui peuvent guérir ; une configuration invalide doit alerter, pas boucler silencieusement.

Ne pas chaîner les migrations

Le web ne doit pas attendre qu’un autre replica lance une migration destructive. Un job unique applique des étapes compatibles, puis les workloads s’ouvrent. Si le schéma requis manque, readiness échoue avec un diagnostic. Cette séquence conserve un rollback applicatif réel.

Définir une santé propre à chaque rôle

Le web vérifie qu’il peut traiter une requête locale. Le worker expose qu’il consomme et renouvelle un heartbeat sans promettre que toutes les dépendances répondent. Le scheduler prouve sa dernière boucle et le prochain déclenchement. Utiliser la même URL health pour tous produit un vert trompeur.

Liveness répond à un blocage du processus ; readiness décide si le trafic ou le travail doit arriver. Un redémarrage ne doit pas remplacer une alerte métier. Si un worker redémarre cinq fois en dix minutes, ce seuil local gèle l’extension et ouvre une analyse de message, mémoire et dépendance.

Conserver une marge d’arrêt

Le monitoring compare durée haute des jobs et grace period. Il signale les traitements qui dépassent régulièrement la fenêtre de déploiement. Le correctif peut découper le job, prolonger le délai ou ajouter un protocole de checkpoint, mais pas simplement tuer plus vite.

Dimensionner sans laisser un service affamer les autres

Web et workers ont des profils différents. Les limites CPU et mémoire évitent qu’une conversion sature le nœud, tandis que les requests ou réservations rendent la capacité planifiable. Les pools SQL, clients HTTP et descripteurs sont intégrés au calcul. Un autoscaling qui ignore ces ressources déplace le goulot.

La concurrence se règle par expérience représentative. Le pilote augmente les workers jusqu’au point où latence SQL, quota partenaire ou mémoire dégrade la promesse. Le seuil retenu garde une marge et reste local à l’infrastructure. Il est révisé après changement de code ou de volume.

Isoler le travail lourd

Une famille de workers dédiée suffit souvent : même image, commande et file distinctes, ressources adaptées. Extraire un microservice uniquement pour obtenir une limite CPU ajoute contrat réseau et déploiement sans valeur métier. L’isolation opérationnelle précède la séparation du code.

Déployer des versions compatibles avec le travail en attente

Une file traverse les déploiements. Le nouveau consommateur doit comprendre les messages anciens ou l’ancienne version reste active jusqu’à drainage. Ajouter un champ optionnel est généralement plus sûr que changer le sens d’une valeur. Un type incompatible reçoit une nouvelle version et une migration explicite.

Le rollout du web peut être rapide tandis qu’un worker finit un message long. Le pipeline associe digest, schéma de message et migrations. Le rollback vérifie que l’ancienne version comprend les données et messages déjà produits. Revenir au tag précédent sans ce contrôle peut aggraver l’incident.

Canariser par catégorie

Un nouveau handler peut consommer une file ou un type borné. Le monitoring compare erreurs, durée et effets doubles. L’équipe élargit après un nombre de cas représentatif, sans inventer une garantie statistique. Le repli remet le routage précédent sans perdre les commandes acceptées.

Cas concret : commandes web, exports et factures

Cas concret hypothétique. Un portail reçoit des commandes, transmet à un ERP, génère les factures et exporte un reporting chaque nuit. Le web et tous les jobs partagent un conteneur supervisé par un script. Un export de quarante minutes bloque le redémarrage, tandis que deux crons lancent parfois la même période.

La cible utilise une image. Le web sert l’API ; des workers « intégration » et « document » consomment deux files ; un scheduler publie ExporterJour avec la date comme clé. Les statuts commande, facture et export vivent en base. Chaque service a ressources, santé, arrêt et tableau propres, avec corrélation commune.

Le pilote traite mille commandes, cent factures et cinq exports. Les seuils locaux exigent zéro transmission ERP doublée, aucun export concurrent pour une date, un diagnostic sous dix minutes et un déploiement sans message perdu. Scénario supplémentaire : si le worker tombe après l’envoi ERP, alors la redélivrance doit rapprocher la référence avant toute nouvelle émission.

Donner au support une chronologie commune

Le support recherche une corrélation et voit demande web, message, tentative, effet externe et statut métier. Il ne choisit pas un conteneur au hasard. Les logs ajoutent rôle, digest, file et catégorie d’erreur sans exposer le payload sensible. Les métriques ouvrent le runbook correspondant.

La mise en œuvre attribue responsabilités du web, des workers, du scheduler et du broker. Elle documente entrées, sorties, dépendances, monitoring, seuils, retries et rollback. Deux paragraphes de runbook valent mieux que vingt services sans owner si une personne différente peut reprendre le cas.

Répéter depuis les droits réels

Le support traite donnée refusée, dépendance silencieuse et message redélivré avec son interface. Les actions sont rapprocher, rejouer une commande idempotente ou escalader. Modifier la file ou la base librement reste interdit ; chaque geste laisse auteur et motif.

Reconnaître le bon niveau de séparation

La méthode devient utile dès qu’un dépôt exécute web et tâches de durées ou priorités différentes. Elle est essentielle quand plusieurs files, transformations lourdes et déploiements fréquents coexistent. La séparation protège capacité et reprise sans exiger plusieurs applications.

Un petit site avec une commande quotidienne courte peut garder web et cron sur une plateforme simple si le déclenchement et le résultat sont visibles. Créer un broker et trois workers pour envoyer dix emails augmente le run. Le seuil dépend de la douleur et de la promesse, pas d’un diagramme idéal.

Erreurs fréquentes d’une architecture multi-services

Lancer plusieurs daemons dans le même conteneur

Un superviseur interne masque codes de sortie et signaux. Chaque rôle principal mérite un service distinct, même s’il partage l’image.

Faire exécuter le métier par le cron

Le planificateur devient impossible à reprendre et double le travail lors d’un chevauchement. Il publie une intention idempotente dont le résultat est suivi.

Utiliser le redémarrage comme correction

Le conteneur repart mais le message, la donnée ou le partenaire reste défaillant. L’alerte doit nommer la cause et l’action, pas seulement le nombre de restarts.

Décider quels processus isoler

La matrice compare commande, durée, priorité, dépendances, profil de ressources, concurrence, arrêt et propriétaire. Deux workloads restent ensemble si leurs limites et leur cycle coïncident. Ils se séparent lorsqu’un incident ou une montée de charge doit être contenu indépendamment.

  1. D’abord, conserver une image commune tant que runtime et version restent identiques.
  2. Ensuite, isoler commandes et ressources selon la promesse de chaque workload.
  3. Puis, différer une nouvelle file tant qu’elle ne protège ni priorité ni reprise.
  4. Enfin, refuser tout service sans santé, owner, arrêt et statut métier observables.

Un conteneur distinct n’est pas un microservice. Cette isolation peut rester dans le même dépôt, la même transaction et le même déploiement. La séparation réseau ne devient pertinente que si données, contrat et équipe ont une autonomie réelle.

Plan d’action sur six semaines

Semaine une : inventorier les exécutions

L’équipe relève commandes, horaires, files, durées, effets, ressources et incidents. Elle choisit un flux critique et nomme les états visibles. Les scripts sans propriétaire et les écritures locales sont bloqués pour les nouveaux cas.

Semaines deux et trois : fermer les contrats

Une image sert des commandes explicites. Le scheduler publie, les workers deviennent idempotents et les files reçoivent erreurs qualifiées. Les healthchecks, signaux et grace periods sont testés. La journalisation relie web, messages et sorties.

Semaine quatre : casser la chaîne

Le pilote coupe broker et partenaire, tue un worker après effet, chevauche un cron et déploie avec un ancien message. Le support exécute rapprochement, retry ou repli depuis le runbook. Les doubles effets bloquent l’ouverture.

Semaines cinq et six : mesurer et étendre

Un trafic borné suit âge, latence, restarts, saturation et temps de diagnostic. Le comité compare les seuils puis augmente une catégorie à la fois. Le dossier attribue ressources, monitoring, contrats et rollback.

La sortie contient carte des workloads, commandes, images, files, matrice de ressources, états, alertes et compatibilité de déploiement. Chaque exception reçoit une échéance. Le plan ne s’achève pas au démarrage des conteneurs, mais quand une personne extérieure au chantier reprend un incident complet.

  1. D’abord, tester le remplacement du web sans perdre une session ni un upload.
  2. Ensuite, provoquer la redélivrance après un effet externe.
  3. Puis, rejouer le retard du scheduler et le budget de rattrapage.
  4. Enfin, décider l’extension depuis le délai métier et la reprise observée.

Guides complémentaires pour tenir le run

Stabiliser l’artefact

Partager l’image entre dev, CI et production évite que chaque rôle dérive vers un runtime différent.

Approfondir la messagerie

Maîtriser Messenger dans le run détaille idempotence, failure transport et reprise support.

Observer les statuts

Observer un workflow métier relie les métriques techniques à la sortie attendue par l’utilisateur.

  • Nommer le rôle avant de créer un nouveau service.
  • Tester signaux, redélivrance et compatibilité de message.
  • Élargir seulement si le support retrouve la causalité sans accès libre à la base.

Conclusion : séparer l’exécution, conserver la causalité

Web, workers et tâches planifiées ont des rythmes et des pannes différents. Les séparer protège ressources, arrêt et déploiement, tout en conservant une image et un vocabulaire communs.

La file ne remplace ni l’état métier ni la reprise. Chaque message doit tolérer la redélivrance, chaque cron expliciter le rattrapage et chaque service exposer une santé adaptée à son rôle.

Le bon nombre de conteneurs est celui dont l’équipe peut expliquer les responsabilités et les incidents. Une topologie plus grande n’apporte aucune maturité si elle disperse les traces et les owners.

Dawap peut cartographier les workloads, fermer un premier flux et répéter son incident dans un accompagnement en développement web sur mesure qui isole les pannes sans perdre la décision métier ni la capacité de reprise.

Portrait de Jérémy Chomel

Vous avez un projet de
développement sur mesure ?

Dawap transforme ce besoin en périmètre livrable, architecture maintenable et trajectoire de mise en production adaptée à vos contraintes.

Besoin d’échanger sur votre projet ? Planifier un rendez-vous

Articles recommandés

Observabilité fonctionnelle d’un workflow métier de bout en bout Développement web Observabilité d’un workflow métier : voir le dossier réel Lire l'article
  • 17 juillet 2026
  • Lecture ~17 min

Logs techniques et disponibilité ne suffisent pas. Instrumentez états, transitions, décisions, délais et reprises pour expliquer où un dossier métier s’est réellement bloqué. Le guide relie événements fonctionnels, traces, métriques, alertes et modes opératoires sans transformer les données personnelles en identifiants de corrélation.

Stratégie de test d’un workflow métier à nombreuses exceptions Développement web Tester un workflow complexe sans explosion combinatoire Lire l'article
  • 17 juillet 2026
  • Lecture ~17 min

Testez les états, transitions, invariants, droits, données et reprises qui portent le risque réel, au lieu de multiplier des scénarios impossibles à maintenir. Cette méthode construit une couverture défendable, injecte les pannes utiles et vérifie aussi les compensations, la concurrence et les preuves attendues par le métier.

Migration progressive d’une application Symfony sans interruption du run Développement web Migration Symfony : monter de version sans casser le run Lire l'article
  • 16 juillet 2026
  • Lecture ~14 min

Une montée de version Symfony touche PHP, dépendances, configuration, données, sessions, cache, Messenger, crons et contrats API. Ce guide propose une trajectoire progressive, une baseline de tests, des critères de retour arrière et une matrice go ou no-go pour moderniser l’application sans confondre migration du framework et refonte métier.

Performance et monitoring d’une application métier Développement web Performance et monitoring d’une application métier Lire l'article
  • 20 janvier 2025
  • Lecture ~45 min

La performance d’une application métier se juge sur la tâche accomplie, pas sur une moyenne globale. Reliez latence, erreurs, saturation et signaux métier, puis définissez les alertes qui déclenchent une action. Traces, métriques et journaux deviennent alors un outil de diagnostic, de dégradation maîtrisée et de reprise.