Queue-SQL : un package qui répartit les UPDATE et DELETE massifs de Laravel sur des jobs parallèles
Queue-SQL, un package Laravel de Kamran Atayev, découpe les UPDATE et DELETE volumineux en tranches de clés primaires traitées en parallèle via le batching natif de Laravel.
Il propose une macro queue(), un suivi CLI, un aperçu dry-run et du tagging Horizon ; il requiert PHP 8.1+ et Laravel 10 à 13.
Exécuter un UPDATE ou un DELETE unique sur des millions de lignes peut bloquer la base pendant des minutes, faire prendre du retard aux réplicas ou expirer en plein déploiement. Queue-SQL, un package Laravel de Kamran Atayev, y répond en découpant les grosses écritures en jobs parallèles : il détermine les clés primaires minimale et maximale de la requête, découpe cette plage d'ID en tranches bornées et envoie un Illuminate\Bus\Batch qui traite chaque tranche indépendamment.
Le package enregistre une macro queue() sur le Query Builder et Eloquent, exposant update, delete, insert et upsert. Les contraintes sont compilées en fragments SQL et bindings, si bien que closures imbriquées, whereHas, whereExists et sous-requêtes parviennent aux workers sans problème de sérialisation. Le dimensionnement des jobs se fait via chunk (lignes par job) ou maxJobs (nombre total cible sur la plage de clés) ; les deux combinés déclenchent une InvalidArgumentException. dispatch() retourne un Illuminate\Bus\Batch natif avec then, catch, finally et allowFailures.
L'usage consiste à chaîner queue() avant la méthode d'écriture et à terminer par dispatch() — rien n'est mis en file avant. Exemple : Order::where('status', 'complete')->queue(chunk: 25000, tries: 2, onQueue: 'maintenance', throttle: 4)->update(['status' => 'completed'])->dispatch(). L'option throttle limite les jobs par seconde, protégeant connexions et réplicas lors des gros backfills. Les suppressions utilisent la même syntaxe ; les insertions en masse ignorent la planification par plage de clés et répartissent le tableau d'enregistrements entre les jobs.
Comme chaque job d'update ou de delete cible une tranche de clés fixe, les retries sont idempotents. Ce n'est pas le cas des insertions, qui peuvent créer des doublons — la documentation recommande un index unique ou upsert() quand la sûreté des retries compte. Comparé au trait Prunable et à la commande model:prune de Laravel, qui suppriment séquentiellement dans un seul processus, Queue-SQL fonctionne en parallèle, suit la progression en batch et gère aussi les updates arbitraires et les insertions en masse.
Remplacer dispatch() par dryRun() prévisualise le plan de batching (opération, table, nombre de jobs, plages, lignes estimées) sans rien mettre en file. Le découpage par plage de clés repose sur les valeurs min/max des clés plutôt que sur des comptages exacts : sur les tables avec de grands trous d'ID, certains jobs traitent moins de lignes, mais le nombre total de jobs reste fixe.
La CLI surveille les batches directement dans la table des batches du framework : queue-sql:status liste ou inspecte les batches, queue-sql:cancel en annule un, --watch rafraîchit toutes les deux secondes dans les terminaux interactifs (une seule fois en non-interactif), et --json formate la sortie. Le statut affiche jobs totaux, en attente et échoués, pourcentages de progression et état du batch. Sous Horizon, les jobs sont automatiquement tagués avec queue-sql, le type d'opération et les tables cibles. Les valeurs par défaut (taille de chunk, retries, backoff, throttling, délais, noms de files) se configurent dans config/queue-sql.php.
Le package exige PHP 8.1+ et Laravel 10 à 13, avec SQLite, MySQL et PostgreSQL. Installation via composer require kamranata/queue-sql, puis queue:batches-table et migrate, car il s'appuie sur le batching natif. Deux limites : le découpage exige une clé primaire entière auto-incrémentée (sinon la requête part dans un job unique), et les bornes de clés sont figées au moment du dispatch() — les lignes insérées ensuite avec des ID supérieurs ne sont pas couvertes. Un script de benchmark (benchmarks/lock_duration.php) est fourni ; lors d'un test de suppression de 20 000 lignes sous SQLite, un DELETE non batché a tenu son verrou 3,6 fois plus longtemps que le plus long verrou mesuré par Queue-SQL.
Tribune des lecteurs
Pas encore de contributions — lance le débat.
Lance la discussion
Pas de compte ni de mot de passe — saisis simplement ton adresse e-mail et nous t’envoyons un lien de connexion à usage unique. Première visite ? Tout se met en place automatiquement.
Ton évaluation sera appliquée automatiquement après ta connexion.
Vérifie ta boîte mail
Nous avons envoyé un lien de connexion à …. Ouvre-le sur cet appareil — cet onglet te connectera automatiquement.
En attente de ton clic …
·