
# Workers

Les workers sont des processus de longue durée qui interrogent la base de données pour trouver les tâches en attente, les exécutent et font avancer les workflows. La commande `wp queuety work` s’exécute dans WP-CLI, tandis que la file d’attente elle-même est revendiquée directement depuis MySQL via le meilleur pilote de base de données Queuety disponible.

L’extension installe également une solution de repli WordPress cron par défaut, exécutée une fois par minute, pour les environnements sans accès au shell. Cette page porte sur les workers WP-CLI dédiés, le mode de déploiement recommandé pour un débit supérieur.

## Démarrer un worker

```bash
wp queuety work
```

Cette commande démarre un worker unique sur la file d’attente `default`. Il s’exécute en boucle : il revendique une tâche, l’exécute, puis recommence. Lorsque la file est vide, il attend `QUEUETY_WORKER_SLEEP` seconde (1 par défaut) avant de l’interroger à nouveau.

### Options

| Option | Description |
|---|---|
| `--queue=<queue>` | Queue(s) à traiter, séparées par des virgules pour définir l’ordre de priorité (`default` par défaut) |
| `--once` | Traiter une seule tâche au maximum, puis quitter |
| `--workers=<n>` | Démarrer N processus workers (nécessite les extensions `pcntl` et `posix`) |
| `--min-workers=<n>` | Nombre minimal de workers d’un pool adaptatif. Nécessite `--max-workers` |
| `--max-workers=<n>` | Nombre maximal de workers d’un pool adaptatif |

```bash
# Process a specific queue
wp queuety work --queue=emails

# Process at most one job and exit
wp queuety work --once

# Run 4 concurrent workers
wp queuety work --workers=4

# Scale between 2 and 6 workers as backlog changes
wp queuety work --queue=providers --min-workers=2 --max-workers=6
```

## Priorités entre plusieurs files d’attente

Un seul worker peut traiter plusieurs files d’attente selon leur ordre de priorité. Transmettez une liste de noms de files séparés par des virgules à `--queue` :

```bash
wp queuety work --queue=critical,default,low
```

Le worker tente de revendiquer une tâche dans chaque file, selon l’ordre indiqué. Il vérifie d’abord `critical`. Si `critical` contient une tâche, il la traite. Si `critical` est vide, il passe à `default`, puis à `low`. Ainsi, les files prioritaires se vident toujours avant celles de priorité inférieure.

### Fonctionnement de l’ordre de priorité

À chaque itération, le worker tente de revendiquer une tâche dans la première file de la liste. Si cette file est vide ou en pause, il passe à la suivante et continue ainsi jusqu’à trouver une tâche ou épuiser la liste. Si aucune tâche n’est trouvée, le worker attend et réessaie. Ce modèle applique une priorité stricte : un flux continu de tâches `critical` affamera `default` et `low`. Si les files moins prioritaires doivent garantir un débit, utilisez plutôt des workers dédiés.

### Utiliser plusieurs files avec PHP

Les méthodes `Worker::run()` et `Worker::flush()` acceptent une chaîne ou un tableau :

```php
// Comma-separated string
Queuety::worker()->run( 'critical,default,low' );

// Array
Queuety::worker()->run( [ 'critical', 'default', 'low' ] );

// flush() also supports multi-queue
$count = Queuety::worker()->flush( 'critical,default,low' );
```

### Stratégies de déploiement

**Des workers dédiés par file d’attente** vous donnent un contrôle total sur la concurrence et l’isolation. Chaque file a son propre worker process(es) et ne peut pas être affamée par les autres files :

```ini
[program:queuety-critical]
command=wp queuety work --queue=critical
numprocs=4

[program:queuety-default]
command=wp queuety work --queue=default
numprocs=2

[program:queuety-low]
command=wp queuety work --queue=low
numprocs=1
```

**Un ordre de priorité avec un seul worker** est plus simple à gérer et convient lorsque les files de priorité inférieure peuvent tolérer des délais :

```ini
[program:queuety-worker]
command=wp queuety work --queue=critical,default,low
numprocs=2
```

Vous pouvez aussi combiner les deux approches : des workers dédiés pour `critical` afin de garantir le débit, et un worker utilisant l’ordre de priorité pour tout le reste :

```ini
[program:queuety-critical]
command=wp queuety work --queue=critical
numprocs=2

[program:queuety-fallback]
command=wp queuety work --queue=default,low
numprocs=2
```

## Admission tenant compte des ressources

Les workers ne se contentent pas de revendiquer la prochaine ligne en attente. Avant le démarrage d’une tâche revendiquée, Queuety peut appliquer des contrôles d’admission généraux, fondés sur le groupe de concurrence de la tâche et le profil d’exécution récent de son gestionnaire.

Pour en savoir plus sur le modèle général, notamment sur son interaction avec les métadonnées des tâches et les budgets de workflow, consultez [Gestion des ressources](https://queuety.inline0.dev/fr/docs/features/resource-management).

Un groupe de concurrence fixe un plafond commun à plusieurs gestionnaires ou catégories de tâches. Si vous attribuez le même groupe et la même limite à plusieurs fournisseurs coûteux en ressources, un worker libère les tâches nouvellement revendiquées au lieu de les démarrer lorsque le groupe a atteint son plafond. Cela évite que des files indépendantes ne submergent un même système en aval simplement parce que plusieurs workers sont inactifs.

Les journaux d’exécution récents alimentent également un profil d’admission simple. Lorsque l’admission tenant compte des ressources est activée, Queuety examine la durée moyenne récente et le pic mémoire du gestionnaire qu’il s’apprête à exécuter. Si le worker actuel approche déjà de sa limite mémoire configurée, si le budget pondéré d’une file ou d’un groupe de fournisseurs est atteint, si le conteneur actuel ne semble pas disposer d’assez de mémoire pour le profil observé du gestionnaire, ou si une exécution de type `--once` approche de sa limite de temps, Queuety reporte la tâche au lieu de démarrer un travail peu susceptible de se terminer correctement.

Vous activez cette règle dans la définition du travail, et non dans la commande du worker :

```php
class CallProviderStep implements \Queuety\Step {
    public function handle( array $state ): array {
        // ...
    }

    public function config(): array {
        return [
            'concurrency_group' => 'providers',
            'concurrency_limit' => 3,
            'cost_units' => 5,
        ];
    }
}
```

Les mêmes métadonnées peuvent être associées à des classes de tâches distribuables au moyen de propriétés publiques, ou à une distribution individuelle via `PendingJob::concurrency_group()` et `PendingJob::cost_units()`.

Le profil d’admission côté worker est contrôlé par les constantes suivantes :

| Constante | Description |
|---|---|
| `QUEUETY_RESOURCE_ADMISSION` | Activer ou désactiver les contrôles d’admission fondés sur le profil |
| `QUEUETY_RESOURCE_PROFILE_WINDOW_MINUTES` | Période à examiner pour établir les profils récents des gestionnaires |
| `QUEUETY_RESOURCE_PROFILE_TTL` | Durée de vie du cache des profils récents des gestionnaires |
| `QUEUETY_RESOURCE_MEMORY_HEADROOM_MB` | Marge mémoire réservée avant d’admettre une autre tâche |
| `QUEUETY_RESOURCE_SYSTEM_MEMORY_AWARENESS` | Activer ou désactiver les contrôles au mieux de la mémoire du conteneur ou de l’hôte |
| `QUEUETY_RESOURCE_SYSTEM_MEMORY_HEADROOM_MB` | Marge mémoire système réservée avant d’admettre une autre tâche |
| `QUEUETY_RESOURCE_QUEUE_COST_BUDGETS` | Budgets de coûts pondérés associés au nom de la file d’attente |
| `QUEUETY_RESOURCE_GROUP_COST_BUDGETS` | Budgets de coûts pondérés associés à `concurrency_group` |
| `QUEUETY_RESOURCE_TIME_HEADROOM_MS` | Marge de temps réservée pour les exécutions de workers ponctuelles |

## Cycle de vie des workers

Un worker s’arrête correctement après avoir terminé sa tâche en cours dès que l’une des conditions suivantes est remplie :

| Condition | Configuration |
|---|---|
| Nombre maximal de tâches traitées | `QUEUETY_WORKER_MAX_JOBS` (1000 par défaut) |
| Limite mémoire dépassée | `QUEUETY_WORKER_MAX_MEMORY` (128 Mo par défaut) |

Une fois arrêté, le worker quitte le processus proprement. En production, un gestionnaire de processus le redémarre automatiquement.

Les signaux ne sont pas encore gérés proprement ([#4](https://github.com/inline0/queuety/issues/4)). Un processus `wp queuety work` unique n’installe aucun gestionnaire de signaux ; `SIGTERM` ou `SIGINT` (Ctrl+C) l’arrête donc immédiatement, même au milieu d’une tâche. Cette tâche reste `processing` jusqu’à ce que la récupération des tâches obsolètes la réinitialise après `QUEUETY_STALE_TIMEOUT` secondes ; veillez donc à ce que les gestionnaires puissent être réessayés sans risque. Un pool de workers transmet `SIGTERM` à ses processus enfants, mais ceux-ci ne le traitent pas. Le pool continue donc de fonctionner jusqu’à ce qu’ils s’arrêtent pour l’une des raisons ci-dessus. Pour arrêter un pool, configurez un délai d’arrêt dans votre gestionnaire de processus, à l’issue duquel il envoie `SIGKILL`.

## Concurrence entre plusieurs workers

L’option `--workers=N` crée N processus enfants avec `pcntl_fork()`. Chaque enfant crée sa propre connexion à la base de données et traite les tâches de façon indépendante. Le processus parent surveille les enfants et redémarre ceux qui plantent.

```bash
wp queuety work --queue=default --workers=4
```

Prérequis :
Les extensions `pcntl` et `posix` PHP doivent être installées (sans `pcntl`, la commande échoue avec « pcntl extension is required for --workers=N. »). Chaque enfant utilise sa propre connexion à la base de données ; le réglage MySQL `max_connections` doit donc être adapté à la taille du pool. Les pools adaptatifs (`--min-workers`/`--max-workers`) ont les mêmes prérequis.

## Pools de workers adaptatifs

Les pools adaptatifs maintiennent un nombre minimal de workers prêts à traiter des tâches, puis augmentent ou diminuent leur nombre dans la plage configurée :

```bash
wp queuety work --queue=providers --min-workers=2 --max-workers=6
```

Le processus parent surveille l’arriéré de tâches pouvant être revendiquées dans les files sélectionnées et ajuste le nombre de processus enfants en fonction de cet arriéré, sans dépasser le maximum configuré. Lorsque l’activité de la file diminue, le pool attend la fin du délai d’inactivité avant de réduire ses effectifs, afin que les courtes pointes d’activité ne provoquent pas un renouvellement immédiat des processus.

La montée en charge reste prudente. Lorsque Queuety peut lire les données de télémétrie mémoire du conteneur ou de l’hôte, il refuse d’ajouter des processus enfants s’il ne reste pas assez de mémoire pour un worker supplémentaire.

La boucle de mise à l’échelle côté parent est contrôlée par :

| Constante | Description |
|---|---|
| `QUEUETY_WORKER_POOL_SCALE_INTERVAL` | Fréquence à laquelle le processus parent ajuste la taille du pool |
| `QUEUETY_WORKER_POOL_IDLE_GRACE` | Durée pendant laquelle l’arriéré doit rester inactif avant la réduction du pool |

## Récupération des tâches obsolètes

Si un worker plante pendant le traitement d’une tâche, celle-ci reste à l’état `processing`. Un worker de longue durée vérifie environ une fois par minute si des tâches sont restées à l’état `processing` plus de `QUEUETY_STALE_TIMEOUT` secondes. Une tâche obsolète ayant encore des tentatives disponibles est réessayée après le délai de temporisation ; si toutes ses tentatives ont été utilisées, elle est mise en attente et son workflow est marqué comme ayant échoué. Les workers `--once` et la solution de repli WP-Cron n’effectuent pas cette vérification.

Récupérez manuellement les tâches obsolètes :

```bash
wp queuety recover
```

## Mode de vidage

Traitez toutes les tâches en attente, puis quittez le processus. Pratique pour les tests ou le traitement ponctuel par lots :

```bash
wp queuety flush
wp queuety flush --queue=emails
```

## Déploiement en production

En production, utilisez un gestionnaire de processus pour maintenir les workers en fonctionnement. Voici deux approches courantes.

### Supervisord

```ini
[program:queuety-default]
command=wp queuety work --queue=default
directory=/var/www/html
autostart=true
autorestart=true
numprocs=2
process_name=%(program_name)s_%(process_num)02d
stdout_logfile=/var/log/queuety-default.log
stderr_logfile=/var/log/queuety-default-error.log

[program:queuety-emails]
command=wp queuety work --queue=emails
directory=/var/www/html
autostart=true
autorestart=true
numprocs=1
stdout_logfile=/var/log/queuety-emails.log
stderr_logfile=/var/log/queuety-emails-error.log
```

### Systemd

```ini
[Unit]
Description=Queuety Worker (default queue)
After=mysql.service

[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/html
ExecStart=/usr/local/bin/wp queuety work --queue=default
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
```

Activez et démarrez :

```bash
sudo systemctl enable queuety-worker
sudo systemctl start queuety-worker
```

### Conseils de déploiement

Lancez des workers distincts pour chaque file lorsque vous avez besoin d’une isolation renforcée. Utilisez `--workers=N` pour les charges de travail limitées par le processeur et privilégiez les workers supervisés individuellement lorsque la charge repose principalement sur les entrées-sorties. Définissez `QUEUETY_WORKER_MAX_JOBS` si vous souhaitez des redémarrages périodiques pour libérer de la mémoire, et surveillez le nombre de `buried` dans [webhooks](https://queuety.inline0.dev/fr/docs/features/webhooks) ou [métriques](https://queuety.inline0.dev/fr/docs/features/metrics).
