Passer au contenu
DedicatedPHP Contact

Priorités dans les files PHP sans bloquer les tâches urgentes

Concevez des priorités dans les files PHP pour isoler les tâches urgentes, maîtriser la capacité, éviter la famine et répondre aux pics de charge.

Diagramme éditorial de files PHP séparées par priorité avec des workers pour les tâches critiques, interactives et massives

Une file asynchrone évite qu’une requête web attende la fin de tâches coûteuses, mais elle ne résout pas à elle seule la concurrence entre les travaux. Le problème apparaît lorsqu’une importation, un retraitement ou une campagne crée des milliers de messages et mobilise tous les consommateurs. Une action à impact immédiat — confirmer une commande, réserver des stocks, bloquer un compte ou envoyer une notification transactionnelle — se retrouve derrière un travail qui peut attendre.

Gérer les priorités dans les files PHP ne consiste pas uniquement à ajouter un champ numérique au message. C’est une décision d’architecture qui doit refléter le flux métier, protéger les dépendances limitées et maintenir un comportement prévisible lorsque la charge augmente.

Classez le travail selon l’impact, l’échéance et le coût

Classez le travail selon l’impact, l’échéance et le coût — guía visual de DedicatedPHP

Avant de créer des files, établissez un inventaire des travaux asynchrones. Pour chacun, identifiez qui l’initie, quelle dépendance il utilise, combien de temps il dure habituellement, quelle est son échéance métier et ce qui se produit s’il est retardé. L’urgence n’équivaut pas nécessairement à l’importance : un rapprochement financier peut être très important, tout en tolérant plusieurs heures d’attente ; une validation de paiement peut nécessiter une réponse rapide, même si son exécution est brève.

Une classification utile inclut généralement quatre classes de service :

  • Critique : actions qui protègent l’argent, la sécurité, la cohérence ou des engagements immédiats. Elles doivent avoir un objectif d’attente très faible et une capacité réservée.
  • Interactive : travail initié par une personne ou nécessaire pour achever une expérience proche du temps réel, comme générer un document demandé depuis l’application.
  • Différée : tâches nécessaires, mais sans échéance immédiate, comme des synchronisations périodiques, des synthèses ou des mises à jour d’index.
  • Massive : importations, migrations, réindexations, campagnes et retraitements. Leur volume ou leur coût impose de limiter leur cadence, même en l’absence d’autre charge.

Consignez également le coût par travail. Un message qui appelle une API avec un quota limité, exécute une requête intensive ou traite un fichier volumineux ne doit pas concurrencer de la même manière qu’une brève mise à jour locale. La classe de service doit exprimer l’échéance et le type de pression que le travail exerce sur le système.

Séparez les files lorsque vous avez besoin d’une véritable isolation

Une file unique avec des priorités peut convenir si les travaux ont une exécution homogène, utilisent les mêmes dépendances et si le transport offre une priorité fiable. Toutefois, l’ordre de récupération ne garantit pas à lui seul qu’il existe de la capacité : un travail massif déjà en cours d’exécution continuera d’occuper un worker, une connexion ou un quota externe.

Séparez les files lorsqu’une de ces limites existe :

  • Les travaux critiques et massifs ont des objectifs d’attente clairement différents.
  • Un type de travail accède à une dépendance fragile ou soumise à des limites de débit, comme une API de paiement, de messagerie ou un ERP.
  • La durée est très inégale et les travaux longs retiennent les processus trop longtemps.
  • Un contrôle indépendant du déploiement, de la mise en pause, de la relance ou de la montée en charge est requis.
  • Une erreur ou une entrée anormale d’un flux ne doit pas dégrader un autre flux.

Dans une application PHP, le modèle le plus lisible consiste généralement à router les messages vers des files explicites, par exemple critical, interactive, deferred et bulk. Le composant de messagerie peut être Symfony Messenger, Laravel Queues ou une intégration spécifique avec le broker choisi ; le principe ne dépend pas du framework. La priorité au sein d’une file peut compléter cette séparation afin d’ordonner des travaux similaires, sans remplacer l’isolation entre des classes incompatibles.

Définissez une capacité réservée et une concurrence maximale

Attribuez des consommateurs par classe et définissez à la fois des minimums et des maximums opérationnels. La file critique a besoin d’une capacité qui ne puisse pas être absorbée par les importations. La file massive, en revanche, doit disposer d’un maximum de concurrence afin de ne pas saturer la base de données, le CPU, le stockage ou les fournisseurs externes.

Évitez de configurer tous les workers pour lire toutes les files avec une préférence absolue pour la file critique. Cette approche peut laisser de la capacité inutilisée si les consommateurs réservés ne peuvent pas prendre d’autres travaux, ou provoquer une famine s’ils peuvent le faire sans règles. Une alternative pratique consiste à combiner :

  • Des workers dédiés aux tâches critiques et interactives.
  • Des workers partagés qui traitent les tâches différées et massives selon des quotas.
  • Des limites par type de dépendance, et pas seulement par nombre total de processus.
  • Une montée en charge fondée sur la profondeur des files et l’ancienneté des messages, et non exclusivement sur l’utilisation du CPU.

Le nombre adéquat n’est pas universel. Il doit partir de la concurrence que la base de données et les API tolèrent, de la durée observée et de l’objectif d’attente de chaque classe.

Évitez la famine et appliquez du backpressure

Accorder la préférence à l’urgent ne signifie pas que le travail différé ne doit jamais se terminer. S’il y a toujours des messages critiques, une politique de priorité stricte peut produire une famine : les travaux de niveau inférieur vieillissent indéfiniment. Établissez une règle d’équité mesurable, comme traiter un quota de messages différés après un nombre limité de messages critiques, ou réserver une petite fraction de la capacité au travail non urgent.

La règle doit respecter les limites des dépendances. Si les tâches critiques et massives écrivent dans la même table avec des verrous coûteux, les exécuter en parallèle peut dégrader la latence. Dans ce cas, le quota doit être appliqué à la ressource partagée, ou il convient de repenser le travail en lots plus petits.

Le backpressure apparaît lorsque davantage de travail arrive que ce qui peut être achevé. Il ne se corrige pas en augmentant indéfiniment le nombre de workers. Définissez comment réagir :

  • Limitez la taille, la fréquence ou la concurrence des importations à la source.
  • Découpez les lots en unités reprenables et contrôlez combien sont publiées à la fois.
  • Reportez le travail différé avec une planification explicite lorsqu’une file ou une dépendance dépasse un seuil.
  • Respectez les réponses de limite de débit avec des pauses et des relances différées, plutôt que des relances immédiates.
  • Indiquez au produit quand une opération est acceptée pour traitement et quand elle est réellement terminée.

Il est important de distinguer l’acceptation de l’exécution : indiquer qu’une importation a été reçue n’implique pas qu’elle puisse démarrer immédiatement. Cette transparence évite qu’un changement technique soit interprété comme une promesse de disponibilité instantanée.

Contrôlez les relances, la lenteur et l’idempotence

Les relances consomment de la capacité et peuvent devenir une charge prioritaire accidentelle. Classez les erreurs entre transitoires et permanentes. Une interruption temporaire du réseau peut justifier une relance avec une attente croissante et une dispersion dans le temps ; une erreur de validation, une ressource inexistante ou un identifiant révoqué doit être dirigé vers un circuit de révision, et non répété sans fin.

Définissez un temps d’exécution maximal par type de travail. Un job lent ne doit pas retenir un worker indéfiniment. S’il peut être découpé, traitez les pages, fichiers ou segments dans des messages indépendants qui enregistrent la progression. Sinon, utilisez des limites strictes, une annulation sûre et une procédure de révision des travaux épuisés.

La priorité augmente le risque de répéter des effets lorsqu’un producteur renvoie un message ou qu’un consommateur échoue après avoir appelé une API externe. Concevez des handlers idempotents : utilisez une clé d’opération stable, persistez l’état de la transition et faites en sorte qu’un double traitement ait le même effet métier qu’un traitement unique. La déduplication du broker peut réduire les doublons, mais elle ne remplace pas l’idempotence dans l’application ni dans les intégrations externes.

Observez l’attente, pas seulement la taille de la file

Une file courte peut masquer un problème si ses messages les plus anciens attendent trop longtemps ou si les consommateurs échouent constamment. Mesurez, par classe de service, l’ancienneté du message le plus ancien, le temps écoulé entre la publication et le démarrage, la durée d’exécution, le pourcentage d’erreurs, les relances et les travaux envoyés en révision.

Complétez ces métriques avec la concurrence active, la profondeur, le débit entrant et sortant, l’utilisation des connexions, les temps de réponse des dépendances et les limites de débit reçues. Les signaux les plus utiles sont les suivants : l’attente critique dépasse son objectif, la file massive croît alors que son quota est limité, les relances dominent le trafic ou la capacité réservée reste inutilisée pendant les pics d’une autre classe.

Configurez des alertes sur les tendances et les objectifs de service, et pas seulement sur un nombre fixe de messages. Mille messages peuvent être normaux pour une importation ; dix peuvent être graves s’il s’agit de confirmations de commande qui attendent depuis plusieurs minutes.

Exemple de flux partagé et liste de mise en œuvre

Exemple de flux partagé et liste de mise en œuvre — guía visual de DedicatedPHP

Imaginez une plateforme qui traite des commandes urgentes, des notifications et une importation massive de catalogue. Les commandes sont routées vers critical ; les notifications transactionnelles, vers interactive ; et l’importation est fragmentée en pages envoyées vers bulk. Les workers de commandes disposent d’une capacité réservée. L’importation a une concurrence limitée et réduit sa cadence si la latence de la base de données augmente. Les notifications respectent le quota du fournisseur, avec des relances différées. Si un processus se répète, la clé d’opération évite de créer deux réservations ou d’envoyer deux fois le même changement d’état.

Pour introduire ce modèle dans une application existante :

  1. Inventoriez les handlers et attribuez une classe de service fondée sur l’échéance, l’impact et la dépendance.
  2. Mesurez la durée, l’attente et les erreurs avant de modifier le routage.
  3. Séparez d’abord les flux critiques des flux massifs et réservez une capacité minimale.
  4. Définissez des limites de concurrence par dépendance et des politiques de backpressure.
  5. Rendez les effets métier idempotents et limitez les relances ainsi que les temps d’exécution.
  6. Testez les pics de charge, la défaillance de fournisseurs et une entrée massive avant d’activer la nouvelle répartition.
  7. Révisez régulièrement les quotas et les classes : une priorité est une politique métier qui évolue avec le produit.

Le résultat recherché n’est pas que tout soit prioritaire, mais que chaque travail reçoive une capacité et une échéance cohérentes, sans transformer une opération à grand volume en blocage pour le reste de l’activité.

Vous souhaitez appliquer ces idées à votre projet ?Parlons de votre plateforme PHP.
Afficher les services associés