
# Plazos de los flujos de trabajo

Se puede asignar un plazo a los flujos de trabajo. Si un flujo de trabajo en ejecución no finaliza dentro del tiempo especificado, Queuety lo marca como fallido y, de forma opcional, llama a un controlador. Los flujos de trabajo pausados o a la espera de una señal o de otros flujos de trabajo no vencen mientras esperan. Los plazos se comprueban aproximadamente una vez por minuto mediante un proceso `wp queuety work` de larga duración, no mediante los workers de `--once` ni la alternativa de WP-Cron. Esto funciona como un interruptor de hombre muerto para los flujos de trabajo de larga duración que no deben ejecutarse indefinidamente.

## Establecer un plazo

Use `must_complete_within()` en el constructor del flujo de trabajo para establecer la duración máxima permitida. Use `on_deadline()` para registrar un controlador que se ejecuta cuando se supera el plazo.

```php
use Queuety\Queuety;

Queuety::workflow( 'data_import' )
    ->then( FetchDataHandler::class )
    ->then( TransformDataHandler::class )
    ->then( LoadDataHandler::class )
    ->must_complete_within( hours: 24 )
    ->on_deadline( ImportTimeoutHandler::class )
    ->dispatch( [ 'source' => $url ] );
```

El método `must_complete_within()` acepta parámetros con nombre que se suman:

```php
->must_complete_within( hours: 2, minutes: 30 )  // 2.5 hours
->must_complete_within( days: 1 )                 // 24 hours
->must_complete_within( seconds: 3600 )           // 1 hour
->must_complete_within( days: 1, hours: 12 )      // 36 hours
```

## Controlador de plazo

La clase del controlador `on_deadline()` debe implementar un método `handle( array $state ): void`. Recibe el estado público del flujo de trabajo (todas las claves que no comienzan con `_`).

```php
class ImportTimeoutHandler {

    public function handle( array $state ): void {
        // Alert the team.
        wp_mail(
            'ops@example.com',
            'Import workflow timed out',
            'Workflow for source ' . ( $state['source'] ?? 'unknown' ) . ' exceeded its deadline.'
        );

        // Clean up partial work.
        if ( isset( $state['temp_file'] ) ) {
            unlink( $state['temp_file'] );
        }
    }
}
```

El controlador del plazo es opcional. Si solo quiere que el flujo de trabajo falle sin ejecutar lógica personalizada, use `must_complete_within()` sin `on_deadline()`.

## Cómo funciona la comprobación de plazos

El worker comprueba si hay plazos vencidos cada 60 segundos como parte de su ciclo de procesamiento. Cuando encuentra un flujo de trabajo cuyo `status` sigue siendo `running` y cuyo `deadline_at` ya ha pasado, llama al controlador `on_deadline` si hay uno registrado, marca el flujo de trabajo como fallido con el mensaje de error `Deadline exceeded` y registra un evento de log `workflow_deadline_exceeded`. El plazo se almacena como una marca de tiempo `deadline_at` en la fila del flujo de trabajo y se calcula en el momento del despacho a partir de la duración configurada.

## Qué ocurre al vencer el plazo

Cuando un flujo de trabajo supera su plazo, su estado cambia a `failed`, el mensaje de error se establece en `Deadline exceeded`, el controlador del plazo se ejecuta de forma síncrona si hay uno registrado y se registra una entrada de log `workflow_deadline_exceeded`. Los trabajos en ejecución no se interrumpen a mitad de su ejecución, pero el flujo de trabajo no avanzará más allá del límite del paso vencido. Si el propio controlador del plazo lanza una excepción, esta se captura silenciosamente y el flujo de trabajo termina igualmente como fallido.

## Métodos de WorkflowBuilder

| Método | Descripción |
|---|---|
| `must_complete_within( int $seconds = 0, int $minutes = 0, int $hours = 0, int $days = 0 )` | Establece la duración máxima permitida. Se suman todos los parámetros. |
| `on_deadline( string $handler_class )` | Registra un controlador que se llama cuando se supera el plazo. |

## Ejemplo: plazo con reintento

Rara vez resulta útil volver a intentar un flujo de trabajo que ha fallado por superar su plazo. `retry_workflow()` lo restablece a `running` y vuelve a poner en cola el paso fallido, pero no elimina ni amplía el plazo, por lo que la siguiente comprobación, en aproximadamente un minuto, volverá a marcarlo como fallido. En su lugar, despache un flujo de trabajo nuevo.

```php
$status = Queuety::workflow_status( $workflow_id );

if ( 'failed' === $status->status->value ) {
    // Check if it was a deadline failure.
    // You may want to dispatch a new workflow instead of retrying.
    Queuety::retry_workflow( $workflow_id );
}
```

## Plazo y demoras de espera

Los plazos se aplican a toda la duración del flujo de trabajo. Las demoras de espera (`->delay()`) pausan el flujo de trabajo durante un tiempo fijo como parte de la secuencia de pasos. Un flujo de trabajo con una demora de espera de 1 hora y un plazo de 2 horas fallará si los pasos que no están en espera tardan más de 1 hora en total.
