
# Planification

Queuety prend en charge les tâches récurrentes. Au lieu de s’appuyer sur `wp_cron`, les planifications sont stockées dans la base de données et évaluées environ une fois par minute par un processus `wp queuety work` de longue durée (ou par le parent d’un pool de workers). `wp queuety work --once`, `wp queuety flush` et le mécanisme de repli intégré au plugin WP-Cron n’évaluent pas les planifications ([#14](https://github.com/inline0/queuety/issues/14)) ; sans worker de longue durée, exécutez vous-même `wp queuety schedule run`.

## Planification par intervalle

Utilisez `every()` pour les planifications simples fondées sur un intervalle. L’expression peut être n’importe quelle chaîne compatible avec `DateTimeImmutable::modify()` de PHP :

```php
use Queuety\Queuety;

Queuety::schedule( 'cleanup_handler' )
    ->every( '1 hour' )
    ->on_queue( 'maintenance' );

Queuety::schedule( 'sync_inventory' )
    ->every( '30 minutes' )
    ->on_queue( 'sync' );

Queuety::schedule( 'daily_report', [ 'type' => 'summary' ] )
    ->every( '1 day' );
```

## Planification Cron

Utilisez `cron()` pour les expressions cron standard à 5 champs :

```php
// Every day at 3am
Queuety::schedule( 'nightly_cleanup' )
    ->cron( '0 3 * * *' );

// Every Monday at 9am
Queuety::schedule( 'weekly_digest' )
    ->cron( '0 9 * * 1' )
    ->on_queue( 'emails' );

// Every 15 minutes
Queuety::schedule( 'health_check' )
    ->cron( '*/15 * * * *' );
```

## Options de planification

Le générateur `PendingSchedule` prend en charge les méthodes suivantes :

| Méthode | Description |
|---|---|
| `every( string $interval )` | Définir une expression d’intervalle |
| `cron( string $expression )` | Définir une expression cron |
| `on_queue( string $queue )` | Définir la file d’attente cible (par défaut : `'default'`) |
| `overlap( OverlapPolicy $policy )` | Définir la politique de chevauchement (par défaut : `Allow`) |

Vous devez appeler soit `every()`, soit `cron()` avant le déclenchement de la planification. Si aucun des deux n’est défini, une `RuntimeException` est levée.

## Politiques de chevauchement

Lorsqu’une tâche planifiée est toujours en cours (en attente ou en traitement) au moment du déclenchement suivant, la politique de chevauchement détermine la suite. Définissez-la avec la méthode `overlap()` :

```php
use Queuety\Queuety;
use Queuety\Enums\OverlapPolicy;

Queuety::schedule( 'sync_inventory' )
    ->every( '5 minutes' )
    ->overlap( OverlapPolicy::Skip )
    ->on_queue( 'sync' );
```

L’énumération `OverlapPolicy` comporte trois cas :

| Politique | Valeur | Comportement |
|---|---|---|
| `OverlapPolicy::Allow` | `allow` | Déclenche toujours un nouveau job, même si l’exécution précédente est toujours en cours. Il s’agit du comportement par défaut. |
| `OverlapPolicy::Skip` | `skip` | Ignore le déclenchement actuel si le gestionnaire a des jobs en attente ou en traitement. `next_run` est mis à jour normalement afin que la planification reste dans le rythme prévu. |
| `OverlapPolicy::Buffer` | `buffer` | Comme pour Skip, le déclenchement n’a pas lieu et `next_run` avance à la prochaine occurrence prévue. Contrairement à Skip, `last_run` n’est pas mis à jour. |

### Allow (par défaut)

Plusieurs instances du même gestionnaire peuvent s’exécuter simultanément. Utilisez cette option pour les gestionnaires idempotents dont le chevauchement est sans conséquence.

```php
Queuety::schedule( 'send_heartbeat_ping' )
    ->every( '1 minute' )
    ->overlap( OverlapPolicy::Allow );
```

### Skip

Le déclenchement est ignoré sans notification si le gestionnaire est toujours en cours d’exécution. Utilisez cette option lorsqu’une deuxième instance serait inutile ou provoquerait des conflits.

```php
Queuety::schedule( 'rebuild_search_index' )
    ->every( '10 minutes' )
    ->overlap( OverlapPolicy::Skip );
```

### Buffer

Aujourd’hui, cette option se comporte comme Skip : si le gestionnaire a toujours un job en attente ou en traitement, le déclenchement n’a pas lieu et `next_run` passe à la prochaine occurrence prévue. La seule différence est que Buffer laisse `last_run` inchangé, tandis que Skip enregistre le déclenchement ignoré comme dernière exécution.

```php
Queuety::schedule( 'sync_inventory' )
    ->every( '5 minutes' )
    ->overlap( OverlapPolicy::Buffer );
```

## Fonctionnement

Lorsqu’une planification est créée, Queuety la stocke dans la table `queuety_schedules` avec l’expression, le gestionnaire, la charge utile et la prochaine heure d’exécution calculée.

À chaque déclenchement du planificateur (environ une fois par minute dans un worker de longue durée, ou lorsque vous exécutez `wp queuety schedule run`), celui-ci vérifie les planifications dont `next_run` est dépassé. Pour chaque planification arrivée à échéance, il déclenche un nouveau job et met à jour `next_run` avec la prochaine occurrence.

## Gérer les planifications via CLI

```bash
# List all schedules
wp queuety schedule list

# Add a recurring schedule
wp queuety schedule add cleanup_handler --every="1 hour"
wp queuety schedule add nightly_report --cron="0 3 * * *" --queue=reports

# Remove a schedule
wp queuety schedule remove cleanup_handler

# Manually trigger the scheduler
wp queuety schedule run
```

## Gérer les planifications via PHP

```php
// Get the scheduler instance
$scheduler = Queuety::scheduler();

// List all schedules
$schedules = $scheduler->list();

// Remove a schedule by handler name
$scheduler->remove( 'cleanup_handler' );

// Manually trigger a tick
$count = $scheduler->tick();
```

## Charge utile

Les planifications peuvent inclure une charge utile statique transmise à chaque job déclenché :

```php
Queuety::schedule( 'generate_report', [ 'type' => 'daily', 'format' => 'pdf' ] )
    ->every( '1 day' )
    ->on_queue( 'reports' );
```

Chaque fois que la planification se déclenche, un nouveau job est déclenché avec cette charge utile.
