
# PHP API

Tout ce qui se trouve dans Queuety est accessible via la classe statique `Queuety\Queuety`. C’est le point d’entrée unique pour distribuer des tâches, créer des workflows, piloter des machines à états, gérer des files d’attente et accéder aux sous-systèmes internes.

```php
use Queuety\Queuety;
```

## Accès autonome au cœur

Le runtime de Queuety, adossé à une base de données, peut être initialisé en dehors de WordPress.

Cette voie autonome est destinée au cœur d’orchestration :

- tâches et workers (les pools de workers nécessitent aussi les constantes `DB_HOST`, `DB_NAME`, `DB_USER` et `DB_PASSWORD`, voir ci-dessous)
- workflows et signaux
- machines à états et événements
- artefacts, journaux, métriques et planifications

Ce n’est pas un remplacement de l’adaptateur WordPress. `Queuety::on_action()`,
`replace_wp_cron()`, l’initialisation du plugin et le véritable chemin d’enregistrement de `wp queuety ...`
requièrent toujours WordPress.

### `Queuety::init( Connection $conn )`

Initialisez Queuety avec une connexion directe à la base de données.

```php
use Queuety\Connection;
use Queuety\Queuety;

$conn = new Connection(
    host: '127.0.0.1:3306',
    dbname: 'wordpress',
    user: 'root',
    password: 'secret',
    prefix: 'wp_',
);

Queuety::init( $conn );
```

L’argument facultatif `table_prefix` modifie la partie Queuety des noms de tables du runtime pour chaque connexion :

```php
$conn = new Connection(
    host: '127.0.0.1:3306',
    dbname: 'wordpress',
    user: 'root',
    password: 'secret',
    prefix: 'wp_',
    table_prefix: 'themequeue_',
);
```

Cela associe des tables comme `queuety_jobs` à `wp_themequeue_jobs`.

### `Queuety::ensure_schema()`

Assurez-vous que les tables du runtime Queuety existent pour la connexion active.

```php
Queuety::init( $conn );
Queuety::ensure_schema();
```

Pour connaître le modèle complet et la limite WordPress, consultez [Utilisation autonome](https://queuety.inline0.dev/fr/docs/features/standalone-use).

## Tâches

### `Queuety::dispatch( $handler, $payload )`

Distribue une tâche. Accepte une chaîne indiquant le nom d’un gestionnaire ou une instance `Contracts\Job`. Renvoie un générateur `PendingJob` permettant d’enchaîner les options.

```php
// Handler name + payload (original API)
Queuety::dispatch( 'send_email', [ 'to' => 'user@example.com' ] );

// Contracts\Job instance (v0.6.0+)
Queuety::dispatch( new SendEmailJob( to: 'user@example.com' ) );

// With options
Queuety::dispatch( 'send_email', [ 'to' => 'user@example.com' ] )
    ->on_queue( 'emails' )
    ->with_priority( Priority::High )
    ->delay( 300 )
    ->max_attempts( 5 )
    ->rate_limit( 10, 60 )
    ->unique()
    ->after( $other_job_id );

// Get the job ID
$job_id = Queuety::dispatch( 'send_email', $payload )->id();
```

Lorsqu’une instance `Contracts\Job` est transmise, le sérialiseur extrait le FQCN comme nom du gestionnaire et les propriétés publiques comme charge utile. Le paramètre `$payload` est ignoré lorsque `$handler` est une instance `Job`.

### Méthodes de `PendingJob`

| Méthode | Description |
|---|---|
| `on_queue( string $queue )` | Définir la file d’attente cible |
| `with_priority( Priority $priority )` | Définir le niveau de priorité |
| `delay( int $seconds )` | Délai avant que la tâche soit disponible |
| `max_attempts( int $max )` | Nombre maximal de tentatives |
| `rate_limit( int $max, int $window )` | Limite de débit : nombre maximal d’exécutions par fenêtre de secondes |
| `unique()` | Empêcher les distributions en double |
| `after( int $job_id )` | Attendre d’abord la fin d’une autre tâche |
| `concurrency_group( string $group, int $limit )` | Placer la tâche dans un groupe partagé d’admission des workers |
| `cost_units( int $units )` | Associer des métadonnées de coût d’exécution relatif à la distribution |
| `id()` | Forcer la distribution et renvoyer l’identifiant de la tâche |

`concurrency_group()` et `cost_units()` s’intègrent au modèle plus large de [gestion des ressources](https://queuety.inline0.dev/fr/docs/features/resource-management) ; la même distribution peut ainsi participer aux limites de concurrence fondées sur le nombre, aux budgets pondérés des files d’attente ou des fournisseurs, ainsi qu’aux heuristiques d’admission des workers.

### `Queuety::dispatch_sync( $handler, $payload )`

Exécute une tâche de façon synchrone dans le processus actuel, sans l’ajouter à la file d’attente.

```php
// With a Job instance
Queuety::dispatch_sync( new SendEmailJob( to: 'user@example.com', subject: 'Hi', body: 'Hello' ) );

// With a handler name and payload
Queuety::dispatch_sync( 'send_email', [ 'to' => 'user@example.com' ] );
```

La méthode `handle()` de la tâche est appelée directement. Aucune ligne n’est créée dans la base de données, aucun worker n’intervient et aucun intergiciel n’est appliqué.

### `Queuety::batch( $jobs )`

Distribue plusieurs tâches en une seule instruction INSERT multi-lignes.

```php
$job_ids = Queuety::batch( [
    [ 'handler' => 'send_email', 'payload' => [ 'to' => 'a@example.com' ], 'queue' => 'emails' ],
    [ 'handler' => 'send_email', 'payload' => [ 'to' => 'b@example.com' ], 'priority' => 2 ],
] );
```

### `Queuety::create_batch( $jobs )`

Crée un `BatchBuilder` pour distribuer un groupe de tâches avec des fonctions de rappel et le suivi de progression. Consultez [Traitement par lots](https://queuety.inline0.dev/fr/docs/features/batching) pour tous les détails.

```php
$batch = Queuety::create_batch( [
    new ImportUsersJob( $chunk_1 ),
    new ImportUsersJob( $chunk_2 ),
] )
    ->name( 'Import users' )
    ->then( ImportCompleteHandler::class )
    ->catch( ImportFailedHandler::class )
    ->finally( ImportCleanupHandler::class )
    ->allow_failures()
    ->on_queue( 'imports' )
    ->dispatch();
```

### Méthodes de `BatchBuilder`

| Méthode | Renvoie | Description |
|---|---|---|
| `name( string $name )` | `self` | Définir un nom pour le lot |
| `on_queue( string $queue )` | `self` | Définir la file d’attente de toutes les tâches du lot |
| `then( string $handler_class )` | `self` | Gestionnaire appelé lorsque le lot se termine avec succès |
| `catch( string $handler_class )` | `self` | Gestionnaire appelé lorsque la première tâche du lot échoue |
| `finally( string $handler_class )` | `self` | Gestionnaire appelé à la fin du lot, en cas de succès ou d’échec |
| `allow_failures()` | `self` | Autoriser l’exécution de la fonction de rappel `then` même en cas d’échecs |
| `dispatch()` | `Batch` | Créer la ligne du lot et toutes les tâches, puis renvoyer l’objet valeur `Batch` |

### `Queuety::find_batch( $id )`

Recherche un lot par ID. Renvoie un objet valeur `Batch` ou `null`.

```php
$batch = Queuety::find_batch( $batch_id );

if ( null !== $batch ) {
    echo $batch->progress() . '% complete';
}
```

## Contrôle des workers

### `Queuety::run_worker( $queue = 'default', $once = false )`

Lance directement une boucle de worker.

```php
Queuety::run_worker( 'default' );
Queuety::run_worker( 'critical,default', true );
```

### `Queuety::run_worker_pool( $workers, $queue = 'default' )`

Lance directement un pool de workers de taille fixe. Nécessite les extensions `pcntl` et `posix`. Le pool lit les constantes WordPress `DB_HOST`, `DB_NAME`, `DB_USER` et `DB_PASSWORD` pour ses connexions enfants (seuls les préfixes de table proviennent de la connexion initialisée) ; définissez-les donc lorsque vous lancez un pool en dehors de WordPress ([#5](https://github.com/inline0/queuety/issues/5)).

```php
Queuety::run_worker_pool( 4, 'providers' );
```

### `Queuety::run_auto_scaling_worker_pool( $min_workers, $max_workers, $queue = 'default' )`

Lance directement un pool de workers adaptatif. Mêmes exigences que pour `run_worker_pool()`.

```php
Queuety::run_auto_scaling_worker_pool( 2, 6, 'providers' );
```

### Objet valeur `Batch`

| Méthode/Propriété | Type | Description |
|---|---|---|
| `$id` | `int` | ID du lot |
| `$name` | `string\|null` | Nom facultatif du lot |
| `$total_jobs` | `int` | Nombre total de tâches dans le lot |
| `$pending_jobs` | `int` | Tâches encore en attente |
| `$failed_jobs` | `int` | Nombre de tâches en échec |
| `$failed_job_ids` | `array` | ID des tâches en échec |
| `$created_at` | `DateTimeImmutable` | Date de création du lot |
| `$finished_at` | `DateTimeImmutable\|null` | Date de fin du lot |
| `$cancelled_at` | `DateTimeImmutable\|null` | Date d’annulation du lot |
| `progress()` | `int` | Pourcentage d’avancement (0-100) |
| `finished()` | `bool` | Indique si le lot est terminé |
| `has_failures()` | `bool` | Indique si une tâche a échoué |
| `cancelled()` | `bool` | Indique si le lot a été annulé |

### `Queuety::chain( $jobs )`

Crée un `ChainBuilder` pour exécuter les tâches de manière séquentielle. Chaque tâche dépend de la réussite de la tâche précédente.

```php
$first_job_id = Queuety::chain( [
    new FetchDataJob( $url ),
    new ProcessDataJob(),
    new NotifyCompleteJob(),
] )
    ->on_queue( 'pipeline' )
    ->catch( ChainFailedHandler::class )
    ->dispatch();
```

### Méthodes de `ChainBuilder`

| Méthode | Renvoie | Description |
|---|---|---|
| `on_queue( string $queue )` | `self` | Définir la file d’attente de toutes les tâches de la chaîne |
| `catch( string $handler_class )` | `self` | Gestionnaire appelé lorsqu’une tâche de la chaîne est définitivement mise en échec |
| `dispatch()` | `int` | Créer toutes les tâches avec des dépendances séquentielles et renvoyer l’ID de la première tâche |

### `Queuety::retry( $job_id )`

Relance une tâche précise. La réinitialise à l’état `pending`.

```php
Queuety::retry( 42 );
```

### `Queuety::retry_buried()`

Relance toutes les tâches mises en échec. Renvoie le nombre de tâches relancées.

```php
$count = Queuety::retry_buried();
```

### `Queuety::purge( $older_than_days )`

Supprime les tâches terminées. Renvoie le nombre de tâches supprimées.

```php
$count = Queuety::purge();     // uses QUEUETY_RETENTION_DAYS
$count = Queuety::purge( 30 ); // purge jobs older than 30 days
```

## Files d’attente

### `Queuety::stats( $queue )`

Récupère le nombre de tâches regroupées par état.

```php
$stats = Queuety::stats();          // all queues
$stats = Queuety::stats( 'emails' ); // specific queue
// ['pending' => 12, 'processing' => 3, 'completed' => 150, 'failed' => 2, 'buried' => 1]
```

### `Queuety::buried( $queue )`

Récupère toutes les tâches mises en échec.

```php
$jobs = Queuety::buried();
$jobs = Queuety::buried( 'emails' );
```

### `Queuety::pause( $queue )`

Met en pause une file d’attente pour que les workers l’ignorent.

```php
Queuety::pause( 'emails' );
```

### `Queuety::resume( $queue )`

Reprend une file d’attente en pause.

```php
Queuety::resume( 'emails' );
```

### `Queuety::is_paused( $queue )`

Vérifie si une file d’attente est en pause.

```php
if ( Queuety::is_paused( 'emails' ) ) {
    // Queue is paused
}
```

## Workflows

### `Queuety::workflow( $name )`

Commence à créer un workflow. Renvoie un `WorkflowBuilder`.

```php
$workflow_id = Queuety::workflow( 'generate_report' )
    ->then( FetchDataHandler::class )
    ->then( CallLLMHandler::class )
    ->then( FormatOutputHandler::class )
    ->dispatch( [ 'user_id' => 42 ] );
```

### Méthodes de `WorkflowBuilder`

| Méthode | Description |
|---|---|
| `then( string $handler_class, ?string $name = null )` | Ajouter une étape séquentielle. Nom facultatif pour les embranchements conditionnels. |
| `parallel( array $handler_classes )` | Ajouter un groupe d’étapes parallèles. |
| `for_each( string $items_key, string $handler_class, ?string $result_key = null, ForEachMode $mode = ForEachMode::All, ?int $quorum = null, ?string $reducer_class = null, ?string $name = null )` | Ajouter une étape dynamique « pour chaque », qui crée une tâche de branche par élément de l’état du workflow. |
| `repeat_while( string $target_step, ?string $state_key = null, mixed $expected = true, ?string $name = null, ?string $condition_class = null, ?int $max_iterations = null )` | Revenir à une étape nommée antérieure tant qu’une clé d’état publique ou une classe `RepeatCondition` correspond. |
| `repeat_until( string $target_step, ?string $state_key = null, mixed $expected = true, ?string $name = null, ?string $condition_class = null, ?int $max_iterations = null )` | Revenir à une étape nommée antérieure jusqu’à ce qu’une clé d’état publique ou une classe `RepeatCondition` corresponde. |
| `run_workflow( string $workflow_name, WorkflowBuilder $sub_builder )` | Ajouter une étape d’exécution de workflow. |
| `delay( int $seconds = 0, int $minutes = 0, int $hours = 0, int $days = 0 )` | Ajouter une étape de délai persistant. Toutes les durées sont cumulées. |
| `wait_for_signal( string $name, ?string $result_key = null, ?string $step_name = null, array $match_payload = [], ?string $correlation_key = null )` | Ajouter une étape d’attente de signal. `match_payload` et `correlation_key` facultatifs permettent d’ignorer les événements sans rapport. |
| `wait_for_signals( array $signal_names, WaitMode $mode = WaitMode::All, ?string $result_key = null, ?string $name = null, array $match_payload = [], ?string $correlation_key = null )` | Attendre plusieurs signaux, tous ou un seul, avec correspondance facultative de charge utile et corrélation. |
| `wait_for_approval( string $signal_name = 'approval', ?string $result_key = 'approval', ?string $name = null, array $match_payload = [], ?string $correlation_key = null )` | Attendre un signal d’approbation humaine. |
| `wait_for_decision( string $approve_signal = 'approved', string $reject_signal = 'rejected', ?string $result_key = 'decision', ?string $name = null, array $match_payload = [], ?string $correlation_key = null )` | Attendre une approbation ou un rejet et enregistrer une charge utile de décision structurée. |
| `wait_for_input( string $signal_name = 'input', ?string $result_key = 'input', ?string $name = null, array $match_payload = [], ?string $correlation_key = null )` | Attendre un signal de saisie humaine. |
| `wait_for_workflow( int\|string $workflow, ?string $result_key = null, ?string $name = null )` | Attendre la fin d’un workflow indiqué par son ID ou par un ID stocké dans l’état public. |
| `wait_for_workflows( array\|string $workflows, WaitMode $mode = WaitMode::All, ?string $result_key = null, ?string $name = null, ?int $quorum = null )` | Attendre la fin de plusieurs workflows, tous, un seul ou un quorum. |
| `wait_for_workflow_group( string $group_key, WaitMode $mode = WaitMode::All, ?int $quorum = null, ?string $result_key = null, ?string $name = null )` | Attendre un groupe de workflows démarré précédemment, indiqué par sa clé de groupe interne. |
| `start_workflows( string $items_key, WorkflowBuilder $workflow_builder, string $result_key = 'started_workflow_ids', string $payload_key = 'item', bool $inherit_state = true, ?string $name = null, ?string $group_key = null )` | Distribuer un workflow de premier niveau par élément du runtime, avec possibilité d’associer une clé de groupe persistante à l’ensemble démarré. |
| `start_agents( string $items_key, WorkflowBuilder $workflow_builder, string $result_key = 'agent_workflow_ids', string $payload_key = 'agent_task', bool $inherit_state = true, ?string $name = null, ?string $group_key = null )` | Alias orienté agent de `start_workflows()`. |
| `wait_for_agents( array\|string $workflows = 'agent_workflow_ids', WaitMode $mode = WaitMode::All, ?string $result_key = 'agent_results', ?string $name = null, ?int $quorum = null )` | Alias orienté agent de `wait_for_workflows()`. |
| `wait_for_agent_group( string $group_key = 'agents', WaitMode $mode = WaitMode::All, ?int $quorum = null, ?string $result_key = 'agent_results', ?string $name = null )` | Alias orienté agent de `wait_for_workflow_group()`. |
| `version( string $version )` | Associer à la définition du workflow une version au niveau de l’application pour inspection et export. |
| `idempotency_key( string $key )` | Rendre persistante la distribution du workflow à l’aide d’une clé fournie par l’appelant. Une nouvelle distribution avec la même clé renvoie l’ID du workflow d’origine. |
| `max_transitions( int $max )` | Faire échouer le workflow si plus de `$max` transitions d’étape sont terminées. |
| `max_for_each_items( int $max )` | Faire échouer le workflow si une étape `for_each()` tente de créer plus de `$max` éléments. |
| `max_state_bytes( int $bytes )` | Faire échouer le workflow si l’état public dépasse `$bytes`. |
| `max_cost_units( int $max )` | Faire échouer le workflow si les étapes terminées consomment plus de `$max` unités de coût. |
| `max_started_workflows( int $max )` | Faire échouer le workflow avant de distribuer plus de `$max` workflows enfants. |
| `compensate_with( string $handler_class )` | Associer un gestionnaire de compensation à la dernière étape ajoutée. |
| `compensate_on_failure()` | Exécuter automatiquement les compensations des étapes terminées en cas d’échec du workflow. |
| `on_queue( string $queue )` | Définir la file d’attente de toutes les étapes. |
| `with_priority( Priority $priority )` | Définir la priorité de toutes les étapes. |
| `max_attempts( int $max )` | Définir le nombre maximal de tentatives par étape. |
| `on_cancel( string $handler_class )` | Enregistrer une classe de gestionnaire de nettoyage en cas d’annulation. Voir [Annulation](https://queuety.inline0.dev/fr/docs/workflows/cancellation). |
| `prune_state_after( int $steps = 2 )` | Activer l’élagage automatique de l’état. Supprime les sorties d’étape antérieures au seuil. Voir [Élagage de l’état](https://queuety.inline0.dev/fr/docs/features/state-pruning). |
| `must_complete_within( int $seconds = 0, int $minutes = 0, int $hours = 0, int $days = 0 )` | Définir une échéance pour le workflow. Toutes les durées sont cumulées. Voir [Échéances](https://queuety.inline0.dev/fr/docs/workflows/deadlines). |
| `on_deadline( string $handler_class )` | Enregistrer un gestionnaire appelé lorsque l’échéance du workflow est dépassée. Voir [Échéances](https://queuety.inline0.dev/fr/docs/workflows/deadlines). |
| `dispatch( array $initial_payload = [] )` | Distribuer le workflow. Renvoie son ID. |

### `Queuety::workflow_status( $workflow_id )`

Récupère l’état du workflow. Renvoie un objet `WorkflowState` ou `null`.

```php
$state = Queuety::workflow_status( $workflow_id );
echo $state->name;          // 'generate_report'
echo $state->status->value; // 'running'
echo $state->current_step;  // 1
echo $state->total_steps;   // 3
print_r( $state->state );   // accumulated public state array
echo $state->wait_type;     // 'signal' or 'workflow' while blocked
echo $state->wait_mode;     // 'all', 'any', or 'quorum'
echo $state->definition_version; // 'research.v2'
echo $state->definition_hash;    // '4c7a...'
echo $state->idempotency_key;    // 'brief:42:research'
echo $state->artifact_count;     // 2
print_r( $state->budget );       // configured workflow budget + current usage
print_r( $state->wait_details ); // matched/remaining blockers, result key, correlation info
print_r( $state->artifact_keys ); // ['draft', 'citations']
```

`WorkflowState` expose également :

- `waiting_for` : noms des signaux ou ID de workflows qui bloquent actuellement l’exécution
- `current_step_name` : nom configuré de l’étape actuelle, le cas échéant
- `wait_mode` : mode d’attente actuel (`all`, `any` ou `quorum`) pendant le blocage
- `wait_details` : données d’inspection supplémentaires, comme les blocages détectés et ceux qui restent
- `definition_version` : valeur définie par `version()`, le cas échéant
- `definition_hash` : hachage déterministe de la définition du workflow
- `idempotency_key` : clé d’envoi durable, le cas échéant
- `budget` : limites configurées et utilisation actuelle, si les garde-fous sont activés
- `artifact_count` : nombre d’artefacts stockés pour le workflow
- `artifact_keys` : clés des artefacts stockés pour une inspection rapide

### `Queuety::retry_workflow( $workflow_id )`

Relancer un workflow en échec à partir de l’étape qui a échoué.

```php
Queuety::retry_workflow( $workflow_id );
```

Lève `RuntimeException` si le workflow a déjà fait l’objet d’une compensation après un échec.

### `Queuety::pause_workflow( $workflow_id )`

Mettre en pause un workflow en cours d’exécution. Le travail déjà mis en file d’attente pour l’étape actuelle peut encore se terminer, mais les étapes suivantes ne sont pas mises en file d’attente tant que vous n’avez pas repris le workflow.

```php
Queuety::pause_workflow( $workflow_id );
```

### `Queuety::resume_workflow( $workflow_id )`

Reprendre un workflow en pause.

```php
Queuety::resume_workflow( $workflow_id );
```

### `Queuety::cancel_workflow( $workflow_id )`

Annuler un workflow et exécuter tous les gestionnaires de nettoyage enregistrés. Définit le statut sur `cancelled` et place dans les éléments enfouis toutes les tâches en attente ou en cours de traitement associées au workflow.

```php
Queuety::cancel_workflow( $workflow_id );
```

Lève `RuntimeException` si le workflow est déjà `completed` ou `cancelled`. Consultez [Annulation](https://queuety.inline0.dev/fr/docs/workflows/cancellation) pour en savoir plus.

### `Queuety::rewind_workflow( $workflow_id, $to_step )`

Revenir à une étape précédente du workflow et le relancer à partir de là. L’état est restauré depuis le journal d’événements `state_after` pour l’étape indiquée, puis l’étape suivante est mise en file d’attente.

```php
Queuety::rewind_workflow( $workflow_id, to_step: 1 );
```

Lève `RuntimeException` si aucun état enregistré n’existe pour l’étape cible. Nécessite le [journal d’événements du workflow](https://queuety.inline0.dev/fr/docs/workflows/event-log). Consultez [Voyage dans le temps](https://queuety.inline0.dev/fr/docs/workflows/time-travel) pour en savoir plus.

### `Queuety::fork_workflow( $workflow_id )`

Créer une copie indépendante d’un workflow en cours d’exécution, à partir de son état actuel. Renvoie l’ID du nouveau workflow.

```php
$forked_id = Queuety::fork_workflow( $workflow_id );
```

Le workflow créé par bifurcation reçoit son propre ID et fonctionne indépendamment de l’original. Consultez [Bifurcation](https://queuety.inline0.dev/fr/docs/workflows/forking) pour en savoir plus.

### `Queuety::export_workflow( $workflow_id )`

Exporter l’historique complet d’exécution d’un workflow sous forme de tableau sérialisable en JSON. Inclut la ligne du workflow, toutes les tâches, les événements du workflow et les entrées du journal.

```php
$data = Queuety::export_workflow( $workflow_id );
```

Consultez [Exportation et rejeu](https://queuety.inline0.dev/fr/docs/workflows/export-replay) pour connaître la structure JSON et ses cas d’utilisation.

### `Queuety::replay_workflow( $data )`

Rejouer un workflow exporté dans l’environnement actuel. Crée un nouveau workflow à partir des données d’exportation et renvoie son ID.

```php
$new_id = Queuety::replay_workflow( $data );
```

Consultez [Exportation et rejeu](https://queuety.inline0.dev/fr/docs/workflows/export-replay) pour en savoir plus.

### `Queuety::replace_wp_cron()`

Remplacer le système intégré de WordPress cron par le planificateur de Queuety. Intercepte `wp_schedule_event()`, `wp_unschedule_event()` et `wp_get_scheduled_event()`, puis achemine les événements récurrents via le worker Queuety.

```php
Queuety::replace_wp_cron();
```

Fonctionne uniquement lorsque WordPress est chargé. Consultez [Remplacement de WP-Cron](https://queuety.inline0.dev/fr/docs/features/wp-cron) pour en savoir plus.

### `Queuety::restore_wp_cron()`

Rétablir le comportement par défaut de WordPress cron en supprimant les hooks du pont Queuety cron.

```php
Queuety::restore_wp_cron();
```

Consultez [Remplacement de WP-Cron](https://queuety.inline0.dev/fr/docs/features/wp-cron) pour connaître les limites.

### `Queuety::signal( $workflow_id, $name, $data )`

Envoyer un signal à un workflow. Si le workflow attend actuellement ce signal, il reprend immédiatement. Sinon, le signal est stocké et récupéré lorsque le workflow atteint l’étape `wait_for_signal` correspondante.

```php
Queuety::signal( $workflow_id, 'approved' );

// With data merged into workflow state
Queuety::signal( $workflow_id, 'approved', [
    'approved_by' => 'admin@example.com',
] );
```

Consultez [Signaux de workflow](https://queuety.inline0.dev/fr/docs/workflows/signals) pour en savoir plus.

### `Queuety::approve_workflow( $workflow_id, $data = [], $signal_name = 'approval' )`

Enveloppe sémantique autour de `signal()` pour les processus d’approbation.

```php
Queuety::approve_workflow( $workflow_id, [
    'reviewer' => 'editor@example.com',
] );
```

### `Queuety::reject_workflow( $workflow_id, $data = [], $signal_name = 'rejected' )`

Enveloppe sémantique autour de `signal()` pour les processus de rejet.

```php
Queuety::reject_workflow( $workflow_id, [
    'reason' => 'needs citations',
] );
```

### `Queuety::submit_workflow_input( $workflow_id, $data = [], $signal_name = 'input' )`

Enveloppe sémantique autour de `signal()` pour la saisie structurée par un utilisateur.

```php
Queuety::submit_workflow_input( $workflow_id, [
    'notes' => 'Ship after legal review',
] );
```

### `Queuety::put_artifact( $workflow_id, $artifact_key, $content, $kind = 'json', $step_index = null, $metadata = [] )`

Stocker un artefact durable pour un workflow.

```php
Queuety::put_artifact(
    $workflow_id,
    'research_brief',
    [ 'summary' => 'done' ],
    'json',
    metadata: [ 'source' => 'agent' ],
);
```

### `Queuety::put_current_artifact( $artifact_key, $content, $kind = 'json', $metadata = [] )`

Stocker un artefact pour l’étape de workflow en cours d’exécution.

```php
Queuety::put_current_artifact(
    'draft',
    [ 'status' => 'ready' ],
    'json',
);
```

### `Queuety::workflow_artifact( $workflow_id, $artifact_key )`

Récupérer un artefact stocké pour un workflow.

```php
$artifact = Queuety::workflow_artifact( $workflow_id, 'draft' );
```

### `Queuety::workflow_artifacts( $workflow_id, $include_content = false )`

Lister les artefacts d’un workflow.

```php
$artifacts = Queuety::workflow_artifacts( $workflow_id );
```

### `Queuety::delete_workflow_artifact( $workflow_id, $artifact_key )`

Supprimer un artefact d’un workflow.

```php
Queuety::delete_workflow_artifact( $workflow_id, 'draft' );
```

## Machines à états

### `Queuety::machine( $name )`

Commencer à créer une machine à états. Renvoie un `StateMachineBuilder`.

```php
use Queuety\Enums\StateMachineStatus;

$machine_id = Queuety::machine( 'agent_session' )
    ->state( 'awaiting_user' )
    ->on( 'user_message', 'planning' )
    ->state( 'planning' )
    ->action( PlanSessionAction::class )
    ->on( 'planned', 'completed' )
    ->state( 'completed', StateMachineStatus::Completed )
    ->dispatch( [ 'thread_id' => 42 ] );
```

### Méthodes de `StateMachineBuilder`

| Méthode | Description |
|---|---|
| `initial( string $state_name )` | Définir explicitement l’état initial. |
| `state( string $state_name, ?StateMachineStatus $terminal_status = null )` | Commencer à configurer un état. |
| `action( string\|array $action_class )` | Enregistrer une action d’entrée mise en file d’attente pour l’état actuel. Passer un nom de classe ou une définition structurée avec `class`, `payload` et `config` ; le `payload` est transmis à `StateAction::handle()` sous la forme `$payload`. |
| `on( string $event, string $target, string\|array\|null $guard_class = null, ?string $name = null )` | Enregistrer une transition d’événement depuis l’état actuel. La garde accepte la même forme structurée que `action()`. |
| `on_queue( string $queue )` | Définir la file d’attente utilisée pour les actions d’état mises en file. |
| `with_priority( Priority $priority )` | Définir la priorité des actions d’état mises en file. |
| `max_attempts( int $max_attempts )` | Définir la limite de tentatives pour les actions d’état mises en file. |
| `version( string $version )` | Attribuer à la définition de la machine une version au niveau de l’application. |
| `idempotency_key( string $key )` | Rendre l’envoi durable à l’aide d’une clé fournie par l’appelant. Un nouvel envoi avec la même clé renvoie l’ID de machine d’origine. |
| `dispatch( array $initial_state = [] )` | Envoyer la machine et renvoyer son ID. |

Les classes d’action d’entrée d’état peuvent aussi exposer une méthode facultative `config()` avec les mêmes clés de politique de ressources que celles prises en charge par les étapes de workflow : `concurrency_group`, `concurrency_limit` et `cost_units`.

### `Queuety::dispatch_state_machine_definition( $definition, $initial_state = [], $options = [] )`

Envoyer un ensemble de définitions de machine à états sérialisé. La plupart du code d’application devrait privilégier `machine()->dispatch()`. Cette méthode de bas niveau permet aux adaptateurs de démarrer une machine sans dépendre directement du constructeur.

```php
$machine_id = Queuety::dispatch_state_machine_definition(
    $definition,
    [ 'thread_id' => 42 ],
    [ 'idempotency_key' => 'thread:42' ],
);
```

### `Queuety::machine_status( $machine_id )`

Obtenir le statut actuel de la machine. Renvoie un objet `StateMachineState` ou `null`.

```php
$status = Queuety::machine_status( $machine_id );

echo $status->name;               // 'agent_session'
echo $status->status->value;      // 'waiting_event'
echo $status->current_state;      // 'awaiting_review'
print_r( $status->state );        // public machine state
print_r( $status->available_events ); // valid incoming events in the current state
```

`StateMachineState` expose également :

- `definition_version`
- `definition_hash`
- `idempotency_key`
- `error_message`
- `current_action`
- `terminal_status`

### `Queuety::machine_event( $machine_id, $event_name, $payload = [] )`

Envoyer un événement externe à une machine en attente.

```php
Queuety::machine_event(
    $machine_id,
    'approve',
    [
        'approved' => true,
        'reviewer' => 'editor@example.com',
    ]
);
```

La charge utile est accessible aux gardes de transition et fusionnée avec l’état public de la machine lorsque l’événement est accepté.

### `Queuety::list_machines( $limit = 50, $status = null )`

Lister les lignes de machine persistées à des fins d’inspection.

```php
$machines = Queuety::list_machines();
$waiting  = Queuety::list_machines( status: 'waiting_event' );
```

Chaque ligne comprend l’ID de la machine, son nom, son statut, son état actuel, la version de la définition, le hachage de la définition, la clé d’idempotence et les horodatages du cycle de vie.

### `Queuety::machine_timeline( $machine_id, $limit = 100, $offset = 0 )`

Obtenir la chronologie durable des événements d’une machine.

```php
$timeline = Queuety::machine_timeline( $machine_id );
$page_two = Queuety::machine_timeline( $machine_id, 100, 100 );
```

Chaque ligne d’événement contient : `id`, `machine_id`, `job_id`, `state_name`, `handler`, `event`, `event_name`, `transition_name`, `queue`, `attempt`, `input`, `output`, `state_before`, `state_after`, `context`, `artifacts`, `chunks`, `error`, `duration_ms` et `created_at`.

### `Queuety::machine_trace( $machine_id )`

Obtenir un ensemble de traces normalisé pour l’interface de débogage d’une machine à états UI.

```php
$trace = Queuety::machine_trace( $machine_id );
```

La trace contient `machine`, `states` regroupés, `events` bruts, des `jobs` d’action corrélés, `logs`, `artifacts` et `chunks`.

### `Queuety::machine_state_at( $machine_id, $event_id )`

Obtenir l’état public après un événement de trace précis de la machine, ou `null` si aucun résultat n’est trouvé.

```php
$state = Queuety::machine_state_at( $machine_id, $event_id );
```

Consultez [Machines à états](https://queuety.inline0.dev/fr/docs/state-machines) pour le modèle de cycle de vie et des exemples d’utilisation.

## Modèles de workflow

### `Queuety::define_workflow( $name )`

Créer un constructeur de workflow à utiliser comme modèle.

```php
$builder = Queuety::define_workflow( 'onboarding' )
    ->then( CreateAccountHandler::class )
    ->then( SendWelcomeEmailHandler::class );
```

### `Queuety::register_workflow_template( $builder )`

Enregistrer un modèle de workflow.

```php
Queuety::register_workflow_template( $builder );
```

### `Queuety::run_workflow( $name, $payload, $options = [] )`

Envoyer un modèle de workflow enregistré en indiquant son nom. Renvoie l’ID du workflow.

```php
$workflow_id = Queuety::run_workflow( 'onboarding', [ 'email' => 'user@example.com' ] );

$workflow_id = Queuety::run_workflow(
    'onboarding',
    [ 'email' => 'user@example.com' ],
    [ 'idempotency_key' => 'onboarding:user@example.com' ],
);
```

Lève `RuntimeException` si le modèle n’est pas enregistré.

### `Queuety::dispatch_workflow_definition( $definition, $payload, $options = [] )`

Envoyer un workflow à partir d’un ensemble de définitions d’exécution.

La plupart du code d’application devrait privilégier `run_workflow()` ou `workflow()->dispatch()`. Cette méthode de bas niveau permet aux adaptateurs réutilisables d’envoyer une définition de workflow sérialisée sans dépendre des méthodes internes du gestionnaire de workflow.

```php
$workflow_id = Queuety::dispatch_workflow_definition(
    $definition,
    [ 'email' => 'user@example.com' ],
    [ 'idempotency_key' => 'onboarding:user@example.com' ],
);
```

### `Queuety::on_action( $hook, $workflow, $map = null, $when = null, $idempotency_key = null, $priority = 10, $accepted_args = null )`

Enregistrer une action WordPress qui envoie un workflow.

```php
Queuety::on_action(
    'save_post',
    workflow: 'content_review',
    map: static fn ( int $post_id, object $post, bool $update ): array => [
        'post_id' => $post_id,
        'post_type' => $post->post_type,
        'update' => $update,
    ],
    when: static fn ( int $post_id, object $post ): bool => 'post' === $post->post_type,
    idempotency_key: static fn ( int $post_id ): string => "save_post:{$post_id}",
);
```

`$workflow` peut être :

- un nom de modèle de workflow enregistré
- un `WorkflowBuilder` intégré au code

`map`, `when` et `idempotency_key` s’exécutent de façon synchrone dans la requête WordPress actuelle. Seules les étapes du workflow s’exécutent de façon asynchrone après l’envoi.

Consultez [Déclencheurs d’action](https://queuety.inline0.dev/fr/docs/features/action-triggers) pour le guide complet.

### `Queuety::workflow_templates()`

Obtenir le registre des modèles de workflow.

```php
$registry = Queuety::workflow_templates();
$template = $registry->get( 'onboarding' ); // WorkflowTemplate or null
```

### `Queuety::load_workflows( $directory, $recursive )`

Charger et enregistrer tous les fichiers de workflow d’un répertoire. Chaque fichier `.php` doit renvoyer un `WorkflowBuilder`. Renvoie le nombre de workflows enregistrés.

```php
$count = Queuety::load_workflows( __DIR__ . '/workflows/' );
$count = Queuety::load_workflows( __DIR__ . '/workflows/', recursive: true );
```

### `Queuety::load_workflow_file( $file_path )`

Charger et enregistrer un fichier de workflow. Renvoie le `WorkflowTemplate` ou `null` si le fichier ne renvoie pas de constructeur.

```php
$template = Queuety::load_workflow_file( __DIR__ . '/workflows/onboard-user.php' );
```

## Planification

### `Queuety::schedule( $handler, $payload )`

Créer une planification récurrente. Renvoie un constructeur `PendingSchedule`.

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

Queuety::schedule( 'nightly_report' )
    ->cron( '0 3 * * *' )
    ->on_queue( 'reports' );
```

### Méthodes de `PendingSchedule`

| Méthode | Description |
|---|---|
| `every( string $interval )` | Définir une expression d’intervalle (e.g, `1 hour`, `30 minutes`) |
| `cron( string $expression )` | Définir une expression cron à 5 champs |
| `overlap( OverlapPolicy $policy )` | Définir la politique de chevauchement (par défaut : `Allow`). Consultez [Planification](https://queuety.inline0.dev/fr/docs/features/scheduling). |
| `on_queue( string $queue )` | Définir la file d’attente cible (par défaut : `default`) |
| `id()` | Forcer l’envoi et renvoyer l’ID de la planification |

### `Queuety::scheduler()`

Obtenir l’instance interne `Scheduler`.

```php
$scheduler = Queuety::scheduler();
$schedules = $scheduler->list();
$scheduler->remove( 'handler_name' );
$count = $scheduler->tick(); // manually trigger
```

## Enregistrement des gestionnaires

### `Queuety::register( $name, $class )`

Enregistrer une classe de gestionnaire sous un nom.

```php
Queuety::register( 'send_email', SendEmailHandler::class );
```

### `Queuety::discover_handlers( $directory, $namespace )`

Détecter automatiquement et enregistrer les classes de gestionnaire d’un répertoire. Renvoie le nombre de gestionnaires enregistrés.

```php
$count = Queuety::discover_handlers( __DIR__ . '/handlers', 'MyPlugin\\Handlers' );
```

### `Queuety::registry()`

Obtenir le registre des gestionnaires.

```php
$registry = Queuety::registry();
```

## Observabilité

### `Queuety::logger()`

Obtenir l’instance `Logger` pour interroger les entrées du journal.

```php
$logger = Queuety::logger();
$logs   = $logger->for_job( 42 );
$logs   = $logger->for_workflow( 7 );
$logs   = $logger->for_handler( 'send_email', 50 );
$logs   = $logger->for_event( LogEvent::Failed, 50 );
$logs   = $logger->since( new \DateTimeImmutable( '-1 hour' ), 100 );
$count  = $logger->purge( 30 );
```

### `Queuety::metrics()`

Obtenir l’instance `Metrics`.

```php
$stats = Queuety::metrics()->handler_stats( 60 ); // last 60 minutes
```

### `Queuety::webhook_notifier()`

Obtenir l’instance `WebhookNotifier`.

```php
$notifier = Queuety::webhook_notifier();
$id       = $notifier->register( 'job.buried', 'https://hooks.slack.com/...' );
$webhooks = $notifier->list();
$notifier->remove( $id );
```

### `Queuety::rate_limiter()`

Obtenir l’instance `RateLimiter`.

```php
$limiter = Queuety::rate_limiter();
$limiter->register( 'call_openai', 60, 60 );
```

## Cache

### `Queuety::cache()`

Obtenir l’instance du moteur de cache actif.

```php
$cache = Queuety::cache();
$cache->set( 'my_key', 'my_value', 60 );
$value = $cache->get( 'my_key' );
```

### `Queuety::set_cache( $cache )`

Remplacer le moteur de cache. Appelez cette méthode avant `Queuety::init()` pour utiliser une implémentation personnalisée.

```php
Queuety::set_cache( new RedisCache() );
Queuety::init( $connection );
```

### `QUEUETY_CACHE_TTL`

Durée de vie par défaut du cache, en secondes (par défaut : `5`). Définissez cette constante dans `wp-config.php` pour modifier la durée de vie par défaut utilisée par les opérations internes du cache.

```php
define( 'QUEUETY_CACHE_TTL', 10 );
```

Consultez [Mise en cache](https://queuety.inline0.dev/fr/docs/features/caching) pour en savoir plus sur les moteurs et la détection automatique.

## Journal d’événements de la machine à états

### `Queuety::machine_events()`

Obtenir l’instance `StateMachineEventLog`.

```php
$log = Queuety::machine_events();
```

## Journal d’événements du workflow

### `Queuety::workflow_events()`

Obtenir l’instance `WorkflowEventLog`.

```php
$log = Queuety::workflow_events();
```

### `Queuety::workflow_timeline( $workflow_id, $limit = 100, $offset = 0 )`

Obtenir la chronologie complète des événements d’un workflow. Renvoie un tableau de lignes d’événement classées par ID.

```php
$events = Queuety::workflow_timeline( $workflow_id );
$next   = Queuety::workflow_timeline( $workflow_id, 100, 100 );
```

Chaque ligne d’événement contient : `id`, `workflow_id`, `job_id`, `parent_event_id`, `step_index`, `step_name`, `step_type`, `handler`, `event`, `queue`, `attempt`, `input`, `output`, `state_before`, `state_after`, `context`, `artifacts`, `chunks`, `error`, `error_message` (copié depuis `error.message`), `duration_ms` et `created_at`.

### `Queuety::workflow_trace( $workflow_id )`

Obtenir un ensemble de traces normalisé pour l’interface de débogage d’un workflow UI.

```php
$trace = Queuety::workflow_trace( $workflow_id );
```

La trace contient `workflow`, `steps` regroupés, `events` bruts, `jobs`, `logs`, `artifacts`, `chunks`, `signals` et `wait_dependencies`.

### `Queuety::trace_input( $input )`

Définir une entrée au niveau de l’application pour l’étape de workflow en cours d’exécution.

### `Queuety::trace_output( $output )`

Définir une sortie au niveau de l’application pour l’étape de workflow en cours d’exécution.

### `Queuety::trace_context( array $context )`

Fusionner un contexte au niveau de l’application dans l’étape de workflow en cours d’exécution.

### `Queuety::workflow_state_at( $workflow_id, $step_index )`

Obtenir l’état public après la fin ou la reprise d’une étape précise du workflow, ou `null` si aucun résultat n’est trouvé.

```php
$state = Queuety::workflow_state_at( $workflow_id, 2 );
```

Consultez [Journal d’événements du workflow](https://queuety.inline0.dev/fr/docs/workflows/event-log) pour connaître les cas d’utilisation et les commandes CLI.

## Instances internes

Ces méthodes renvoient des instances internes pour les cas d’utilisation avancés.

| Méthode | Renvoie | Description |
|---|---|---|
| `Queuety::queue()` | `Queue` | Opérations de file d’attente (réclamation, libération, enfouissement) |
| `Queuety::worker()` | `Worker` | Contrôle du processus worker |
| `Queuety::workflow_manager()` | `Workflow` | Orchestration des workflows |
| `Queuety::machines()` | `StateMachine` | Gestion du cycle de vie des machines à états |
| `Queuety::connection()` | `Connection` | Connexion à la base de données |
| `Queuety::batch_manager()` | `BatchManager` | Gestion du cycle de vie des lots (annulation, élagage) |
| `Queuety::chunk_store()` | `ChunkStore` | Persistance des blocs pour les étapes en flux continu |
| `Queuety::machine_events()` | `StateMachineEventLog` | Événements de trace des machines à états et ensembles de traces normalisés |
| `Queuety::workflow_events()` | `WorkflowEventLog` | Événements de trace des workflows et ensembles de traces normalisés |
| `Queuety::resource_manager()` | `ResourceManager` | Profils d’admission des workers, budgets pondérés et inspection de la mémoire système |
| `Queuety::cache()` | `Cache` | Instance du moteur de cache |

## Tests

### `Queuety::fake()`

Remplacer la file d’attente par un faux objet en mémoire pour les tests. Renvoie une instance `QueueFake` qui enregistre les tâches envoyées sans accéder à la base de données. `create_batch()` enregistre également les métadonnées fictives des lots ; les chaînes sont vérifiées à partir des tâches envoyées individuellement.

```php
$fake = Queuety::fake();
SendEmailJob::dispatch( 'user@example.com', 'Hello', 'Hi!' );
$fake->assert_pushed( SendEmailJob::class );
```

### `Queuety::reset()`

Réinitialiser tout l’état interne, y compris le faux objet de file d’attente. À appeler dans `tearDown()`.

```php
Queuety::reset();
```

### Méthodes de `QueueFake`

| Méthode | Description |
|---|---|
| `assert_pushed( string $class, ?Closure $callback )` | Vérifier qu’une classe de tâche a été ajoutée. Un callback facultatif filtre les données de la tâche. |
| `assert_pushed_times( string $class, int $count )` | Vérifier qu’une tâche a été ajoutée exactement N fois. |
| `assert_not_pushed( string $class )` | Vérifier qu’une tâche n’a jamais été ajoutée. |
| `assert_nothing_pushed()` | Vérifier qu’aucune tâche n’a été ajoutée. |
| `assert_batched( ?Closure $callback )` | Vérifier qu’un lot a été envoyé. Un callback facultatif filtre les données du lot. |
| `pushed( string $class )` | Obtenir tous les envois enregistrés pour une classe. Renvoie un tableau. |
| `batches()` | Obtenir tous les lots enregistrés. Renvoie un tableau. |
| `reset()` | Effacer toutes les tâches et tous les lots enregistrés. |

Consultez [Tests](https://queuety.inline0.dev/fr/docs/features/testing) pour des exemples complets.

## Interfaces

### `Handler`

Interface pour les gestionnaires de tâches simples.

```php
interface Handler {
    public function handle( array $payload ): void;
    public function config(): array;
}
```

`config()` peut renvoyer `queue`, `max_attempts`, `backoff`, `rate_limit`, `concurrency_group`, `concurrency_limit` et `cost_units`.

### `Step`

Interface pour les gestionnaires d’étapes de workflow.

```php
interface Step {
    public function handle( array $state ): array;
    public function config(): array;
}
```

`config()` peut renvoyer `max_attempts`, `backoff`, `concurrency_group`, `concurrency_limit` et `cost_units`.

### `Contracts\ForEachHandler`

Interface pour les gestionnaires de branches dynamiques de boucle for-each.

```php
namespace Queuety\Contracts;

interface ForEachHandler {
    public function handle_item( array $state, mixed $item, int $index ): array;
    public function config(): array;
}
```

`config()` peut renvoyer `max_attempts`, `backoff`, `rate_limit`, `concurrency_group`, `concurrency_limit` et `cost_units`.

### `Contracts\ForEachReducer`

Réducteur facultatif pour les résultats de boucle for-each.

```php
namespace Queuety\Contracts;

interface ForEachReducer {
    public function reduce( array $state, array $for_each ): array;
}
```

### `Contracts\Compensation`

Interface pour les gestionnaires de compensation des étapes.

```php
namespace Queuety\Contracts;

interface Compensation {
    public function handle( array $state ): void;
}
```

### `Contracts\RepeatCondition`

Interface pour les prédicats de boucle utilisés par `repeat_until()` et `repeat_while()` lorsque la comparaison de clés d’état est trop limitée.

```php
namespace Queuety\Contracts;

interface RepeatCondition {
    public function matches( array $state ): bool;
}
```

### `Contracts\StateAction`

Interface pour les actions d’entrée d’état mises en file d’attente.

```php
namespace Queuety\Contracts;

interface StateAction {
    public function handle( array $state, ?string $event = null, array $event_payload = [], array $payload = [] ): array|string;
}
```

`$payload` transporte la donnée structurée `payload` de la définition de l’action, si la machine en comporte une. Renvoyer les mises à jour de l’état public. Inclure `_event` et éventuellement `_event_payload` si l’action doit déclencher une transition immédiate.

Les actions d’état peuvent aussi définir une méthode facultative `config()`. Queuety y lit `concurrency_group`, `concurrency_limit` et `cost_units` lorsque l’action d’entrée est mise en file d’attente.

### `Contracts\StateGuard`

Interface pour les gardes de transition des machines à états.

```php
namespace Queuety\Contracts;

interface StateGuard {
    public function allows( array $state, array $event_payload, string $event, array $payload = [] ): bool;
}
```

### `Contracts\Job`

Interface pour les classes de tâches autonomes pouvant être envoyées. Les classes de tâches encapsulent leur charge utile sous forme de propriétés publiques et leur logique d’exécution dans `handle()`.

```php
namespace Queuety\Contracts;

interface Job {
    public function handle(): void;
}
```

Les classes de tâches peuvent définir une méthode facultative `middleware()` qui renvoie un tableau d’instances `Contracts\Middleware`.

### `Contracts\Cache`

Interface pour les moteurs de cache. Consultez [Mise en cache](https://queuety.inline0.dev/fr/docs/features/caching) pour connaître les implémentations intégrées et les moteurs personnalisés.

```php
namespace Queuety\Contracts;

interface Cache {
    public function get( string $key ): mixed;
    public function set( string $key, mixed $value, int $ttl = 0 ): void;
    public function delete( string $key ): void;
    public function has( string $key ): bool;
    public function add( string $key, mixed $value, int $ttl = 0 ): bool;
    public function flush(): void;
}
```

| Méthode | Renvoie | Description |
|---|---|---|
| `get( $key )` | `mixed` | Récupérer une valeur. Renvoie `null` si elle est introuvable ou expirée. |
| `set( $key, $value, $ttl )` | `void` | Stocker une valeur. Un TTL de 0 signifie qu’elle n’expire pas. |
| `delete( $key )` | `void` | Supprimer une valeur. |
| `has( $key )` | `bool` | Vérifier si une clé existe et n’a pas expiré. |
| `add( $key, $value, $ttl )` | `bool` | Définir une valeur de façon atomique si elle n’existe pas. Renvoie `true` si la valeur a été définie. |
| `flush()` | `void` | Supprimer tous les éléments du cache. |

### `WorkflowEventLog`

Enregistre les transitions des étapes de workflow avec leur contexte de trace complet. Accessible via `Queuety::workflow_events()`.

| Méthode | Renvoie | Description |
|---|---|---|
| `record_event( array $event )` | `void` | Enregistrer un événement de trace brut |
| `record_step_started( ... )` | `void` | Enregistrer un événement step_started avec l’entrée et l’état avant l’exécution |
| `record_step_completed( ... )` | `void` | Enregistrer un événement step_completed avec l’entrée, la sortie et les états avant et après l’exécution |
| `record_step_failed( ... )` | `void` | Enregistrer un événement step_failed avec le contexte de trace et des détails d’erreur structurés |
| `get_timeline( int $workflow_id, ?int $limit = 100, int $offset = 0 )` | `array` | Obtenir les événements de trace du workflow dans l’ordre, avec pagination facultative |
| `get_trace( int $workflow_id )` | `array` | Obtenir un ensemble de traces normalisé |
| `get_state_at_step( int $workflow_id, int $step_index )` | `array\|null` | Obtenir l’état public après la fin ou la reprise d’une étape précise |
| `prune( int $older_than_days )` | `int` | Supprimer les événements datant de plus que le nombre de jours indiqué. Renvoie le nombre de lignes supprimées. |

### `StateMachineEventLog`

Enregistre les événements du cycle de vie des machines à états, des actions, des transitions et des gardes, avec les mêmes champs de trace que les événements de workflow.

| Méthode | Renvoie | Description |
|---|---|---|
| `record_event( array $event )` | `void` | Enregistre un événement brut de trace machine |
| `get_timeline( int $machine_id, ?int $limit = 100, int $offset = 0 )` | `array` | Récupère les événements de trace machine dans l’ordre, avec pagination facultative |
| `get_trace( int $machine_id )` | `array` | Récupère un ensemble normalisé de traces machine |
| `get_state_at_event( int $machine_id, int $event_id )` | `array\|null` | Récupère l’état public après un événement de trace machine donné |
| `prune( int $older_than_days )` | `int` | Supprime les événements antérieurs au nombre de jours indiqué. Renvoie le nombre de lignes supprimées. |

### `Contracts\StreamingStep`

Interface pour les gestionnaires d’étapes de workflow qui produisent un flux de blocs. Chaque valeur générée est immédiatement enregistrée dans la base de données. Voir [Étapes en flux continu](https://queuety.inline0.dev/fr/docs/workflows/streaming).

```php
namespace Queuety\Contracts;

interface StreamingStep {
    public function stream( array $state, array $existing_chunks = [] ): \Generator;
    public function on_complete( array $chunks, array $state ): array;
    public function config(): array;
}
```

| Méthode | Description |
|---|---|
| `stream( $state, $existing_chunks )` | Générateur qui produit des blocs de chaînes. Chaque génération déclenche une écriture immédiate dans la base de données. En cas de nouvelle tentative, `$existing_chunks` contient les blocs déjà enregistrés. |
| `on_complete( $chunks, $state )` | Appelée une fois le flux terminé. Renvoie des données à fusionner avec l’état du workflow. |
| `config()` | Configuration facultative. Prend en charge `max_attempts`, `backoff`, `concurrency_group`, `concurrency_limit` et `cost_units`. |

### `ChunkStore`

Gère la persistance des blocs pour les étapes en flux continu. Accessible via `Queuety::chunk_store()`.

| Méthode | Renvoie | Description |
|---|---|---|
| `get_chunks( int $job_id )` | `string[]` | Récupère tous les blocs d’une tâche, triés par index de bloc |
| `append_chunk( int $job_id, int $chunk_index, string $content, ?int $workflow_id, ?int $step_index )` | `void` | Ajoute un bloc |
| `clear_chunks( int $job_id )` | `void` | Supprime tous les blocs d’une tâche |
| `chunk_count( int $job_id )` | `int` | Compte les blocs d’une tâche |
| `get_accumulated( int $job_id )` | `string` | Concatène tous les blocs en une seule chaîne |

### `Heartbeat`

Méthode utilitaire statique pour envoyer des signaux de présence depuis les gestionnaires d’étapes et les étapes en flux continu. Voir [Signaux de présence](https://queuety.inline0.dev/fr/docs/features/heartbeats).

| Méthode | Description |
|---|---|
| `Heartbeat::init( int $job_id, Connection $conn )` | Définit le contexte de la tâche. Appelée automatiquement par le processus de travail. |
| `Heartbeat::beat( array $progress = [] )` | Envoie un signal de présence. Met à jour `reserved_at` et enregistre éventuellement les données de progression dans `heartbeat_data`. |
| `Heartbeat::clear()` | Efface le contexte de la tâche. Appelée automatiquement par le processus de travail. |
| `Heartbeat::current_job_id()` | Récupère l’ID de la tâche en cours (pour les tests). |

### `Contracts\Middleware`

Interface pour les intergiciels de tâches. Un intergiciel enveloppe l’exécution d’une tâche dans un pipeline en oignon.

```php
namespace Queuety\Contracts;

interface Middleware {
    public function handle( object $job, \Closure $next ): void;
}
```

## Traits

### `Dispatchable`

Fournit des méthodes de distribution statique pour les classes de tâches qui implémentent `Contracts\Job`. Les arguments du constructeur sont transmis pour créer l’instance de la tâche.

```php
use Queuety\Contracts\Job;
use Queuety\Dispatchable;

class SendEmailJob implements Job {
    use Dispatchable;
    // ...
}

// Dispatches a new SendEmailJob instance
SendEmailJob::dispatch( 'user@example.com', 'Subject', 'Body' );
```

| Méthode | Renvoie | Description |
|---|---|---|
| `dispatch( ...$args )` | `PendingJob` | Crée une instance et la distribue |
| `dispatch_if( bool $condition, ...$args )` | `PendingJob\|null` | Distribue uniquement si `$condition` est vrai |
| `dispatch_unless( bool $condition, ...$args )` | `PendingJob\|null` | Distribue uniquement si `$condition` est faux |
| `with_chain( array $jobs )` | `ChainBuilder` | Démarre une chaîne à partir de cette classe de tâche |

```php
// Conditional dispatch
SendEmailJob::dispatch_if( $user->wants_email, $user->email, 'Hello', 'Hi!' );
SendEmailJob::dispatch_unless( $maintenance_mode, $user->email, 'Hello', 'Hi!' );

// Chain from a job class
FetchDataJob::with_chain( [
    new ProcessDataJob(),
    new NotifyCompleteJob(),
] )->dispatch();
```

### Propriétés des tâches

Les classes de tâches peuvent déclarer des propriétés publiques que le processus de travail lit par réflexion pour remplacer le comportement de nouvelle tentative et de délai d’expiration.

| Propriété | Type | Description |
|---|---|---|
| `$tries` | `int` | Nombre maximal de tentatives avant la mise en quarantaine de la tâche |
| `$timeout` | `int` | Durée d’exécution maximale en secondes (nécessite `pcntl`) |
| `$backoff` | `array` | Valeurs de délai croissantes en secondes pour chaque nouvelle tentative |

```php
class ImportProductsJob implements Job {
    use Dispatchable;

    public int $tries = 5;
    public int $timeout = 120;
    public array $backoff = [ 10, 30, 60, 120 ];

    // ...
}
```

### Hook `failed()`

Lorsqu’une tâche est mise en quarantaine après avoir épuisé toutes ses tentatives, le processus de travail appelle une méthode `failed()` sur l’instance de la tâche si elle est définie.

```php
public function failed( \Throwable $exception ): void {
    error_log( "Job failed: {$exception->getMessage()}" );
}
```

## Intergiciels intégrés

Toutes les classes d’intergiciel implémentent `Contracts\Middleware` et se trouvent dans l’espace de noms `Queuety\Middleware`.

| Classe | Description |
|---|---|
| `RateLimited( int $max, int $window )` | Applique une limite de débit de `$max` exécutions toutes les `$window` secondes |
| `Timeout( int $seconds )` | Arrête la tâche après `$seconds` secondes (nécessite `pcntl`) |
| `UniqueJob( ?string $key )` | Empêche les exécutions simultanées au moyen d’un verrou de base de données |
| `WithoutOverlapping( string $key, int $release_after )` | Empêche les chevauchements d’exécution avec expiration automatique du verrou |
| `ThrottlesExceptions( int $max_attempts, int $decay_minutes )` | Limite les exceptions pour éviter les tempêtes de tâches lorsqu’un service externe est indisponible |

Consultez [Intergiciels](https://queuety.inline0.dev/fr/docs/features/middleware) pour connaître les détails d’utilisation et voir des exemples.

## Énumérations

### `Priority`

```php
enum Priority: int {
    case Low    = 0;
    case Normal = 1;
    case High   = 2;
    case Urgent = 3;
}
```

### `JobStatus`

```php
enum JobStatus: string {
    case Pending    = 'pending';
    case Processing = 'processing';
    case Completed  = 'completed';
    case Failed     = 'failed';
    case Buried     = 'buried';
}
```

### `WorkflowStatus`

```php
enum WorkflowStatus: string {
    case Running        = 'running';
    case Completed      = 'completed';
    case Failed         = 'failed';
    case Paused         = 'paused';
    case WaitingForSignal  = 'waiting_for_signal';
    case WaitingForWorkflows = 'waiting_for_workflows';
    case Cancelled      = 'cancelled';
}
```

### `StateMachineStatus`

```php
enum StateMachineStatus: string {
    case Running = 'running';
    case WaitingEvent = 'waiting_event';
    case Completed = 'completed';
    case Failed = 'failed';
    case Paused = 'paused';
    case Cancelled = 'cancelled';
}
```

### `BackoffStrategy`

```php
enum BackoffStrategy: string {
    case Fixed       = 'fixed';
    case Linear      = 'linear';
    case Exponential = 'exponential';
}
```

### `ForEachMode`

```php
enum ForEachMode: string {
    case All = 'all';
    case FirstSuccess = 'first_success';
    case Quorum = 'quorum';
}
```

### `WaitMode`

```php
enum WaitMode: string {
    case All    = 'all';
    case Any    = 'any';
    case Quorum = 'quorum';
}
```

### `LogEvent`

```php
enum LogEvent: string {
    case Started                  = 'started';
    case Completed                = 'completed';
    case Failed                   = 'failed';
    case Buried                   = 'buried';
    case Retried                  = 'retried';
    case WorkflowStarted          = 'workflow_started';
    case WorkflowCompleted        = 'workflow_completed';
    case WorkflowFailed           = 'workflow_failed';
    case WorkflowPaused           = 'workflow_paused';
    case WorkflowResumed          = 'workflow_resumed';
    case WorkflowCancelled        = 'workflow_cancelled';
    case WorkflowRewound          = 'workflow_rewound';
    case WorkflowForked           = 'workflow_forked';
    case WorkflowDeadlineExceeded = 'workflow_deadline_exceeded';
    case Debug                    = 'debug';
}
```

### `OverlapPolicy`

```php
enum OverlapPolicy: string {
    case Allow  = 'allow';
    case Skip   = 'skip';
    case Buffer = 'buffer';
}
```

Consultez [Planification](https://queuety.inline0.dev/fr/docs/features/scheduling) pour savoir comment fonctionne chaque stratégie.

## Attributs

### `#[QueuetyHandler]`

PHP 8 attribut pour l’enregistrement automatique. Voir [Attributs PHP](https://queuety.inline0.dev/fr/docs/features/attributes).

```php
use Queuety\Attributes\QueuetyHandler;

#[QueuetyHandler( name: 'send_email', queue: 'emails', max_attempts: 5 )]
class SendEmailHandler implements Handler {
    // ...
}
```

## Pont CLI

### `Queuety::cli_command()`

Renvoie le nom publié de la commande racine WP-CLI.

La commande racine par défaut est `queuety`. Définissez `QUEUETY_CLI_COMMAND` avant le démarrage de Queuety si la commande doit être publiée sous un autre nom.

### `Queuety::cli_command_map()`

Renvoie le catalogue sérialisable de commandes Queuety CLI destiné aux environnements de test qui doivent connaître les commandes fournies sans analyser les classes WP-CLI.

Chaque entrée comprend :
- un ID d’opération stable
- le chemin relatif CLI
- la classe et la méthode du gestionnaire WP-CLI
- les cibles d’exécution possibles
- l’adaptateur qui normalise les arguments CLI bruts en un plan d’exécution

### `Queuety::resolve_cli_command( $path, $args, $assoc_args )`

Transforme un appel CLI analysé en plan d’exécution à lancer dans l’environnement de test.

```php
$plan = Queuety::resolve_cli_command(
    [ 'workflow', 'export' ],
    [ '42' ],
    [ 'output' => '/tmp/workflow.json' ]
);

echo $plan['callable']; // Queuety\Queuety::export_workflow_to_file
print_r( $plan['arguments'] );
```

Les plans d’exécution tiennent compte du transport :
- les commandes sont résolues en fonctions appelables publiques PHP avec des arguments normalisés
- le catalogue répertorie à l’avance toutes les cibles d’exécution possibles, tandis que `callable` et `transport` identifient la branche choisie pour l’entrée analysée

C’est le format standard utilisé par Queuety pour les environnements de test d’agents : ID d’opération stable, cible publique API et normalisation gérée par l’adaptateur pour les aspects propres à CLI, tels que les valeurs par défaut des files d’attente, le décodage des données utiles JSON, le choix de branche du pool de processus et la gestion des fichiers d’export de workflow.
