Saltar al contenido

Repeticiones

Queuety workflows son cadenas ordenadas de pasos. Usa un paso de control de repetición para volver a un paso anterior con nombre, en lugar de escribir a mano la lógica de _next_step.

Elige la forma que mejor se adapte al flujo de trabajo:

  • un state_key público cuando la condición es sencilla
  • un condition_class cuando la repetición necesita una lógica más elaborada
  • max_iterations cuando la repetición necesita un límite estricto

Ambos métodos apuntan a un paso anterior con nombre, por lo que la repetición sigue siendo serializable y reproducible, y está protegida por el mismo entorno de ejecución del flujo de trabajo que los demás pasos.

La condición de repetición se evalúa a partir del estado público persistido del flujo de trabajo una vez completado el paso anterior, por lo que cada iteración se conserva aunque se reinicien los workers.

repeat_until() con una clave de estado

PHP
Queuety::workflow( 'approval_revision_loop' )
    ->max_transitions( 12 )
    ->then( DraftBriefStep::class, 'draft' )
    ->wait_for_decision( result_key: 'review' )
    ->then( NormalizeReviewOutcomeStep::class, 'review_outcome' )
    ->repeat_until( 'draft', 'review_approved', true, 'repeat_draft_until_approved' )
    ->then( PublishBriefStep::class )
    ->dispatch( [ 'brief_id' => 42 ] );

NormalizeReviewOutcomeStep puede convertir los datos de decisión en una clave pública sencilla:

PHP
class NormalizeReviewOutcomeStep implements \Queuety\Step {
    public function handle( array $state ): array {
        return [
            'review_approved' => 'approved' === ( $state['review']['outcome'] ?? null ),
        ];
    }

    public function config(): array {
        return [];
    }
}

Si review_approved todavía no es true, el paso de repetición vuelve a draft. Cuando pasa a ser true, el flujo de trabajo continúa en PublishBriefStep.

Las señales se almacenan, no se consumen. En la segunda pasada por wait_for_decision(), la señal anterior de rejected todavía coincide y la espera termina de inmediato, por lo que el bucle se repetiría hasta que max_transitions() lo detuviera. Asigna una clave a cada ronda: haz que DraftBriefStep devuelva un review_round incremental, pasa correlation_key: 'review_round' a wait_for_decision() y haz que el revisor envíe el mismo review_round en los datos de la señal. Así, la espera solo termina cuando review_round coincide con el valor actual del estado.

repeat_until() con una clase de condición

PHP
use App\Workflows\ReviewApprovedCondition;

Queuety::workflow( 'approval_revision_loop' )
    ->then( DraftBriefStep::class, 'draft' )
    ->wait_for_decision( result_key: 'review' )
    ->repeat_until(
        target_step: 'draft',
        condition_class: ReviewApprovedCondition::class,
        max_iterations: 5,
        name: 'repeat_draft_until_approved',
    )
    ->then( PublishBriefStep::class )
    ->dispatch( [ 'brief_id' => 42 ] );
PHP
namespace App\Workflows;

use Queuety\Contracts\RepeatCondition;

final class ReviewApprovedCondition implements RepeatCondition {
    public function matches( array $state ): bool {
        return 'approved' === ( $state['review']['outcome'] ?? null );
    }
}

Las clases de condición reciben el estado público del flujo de trabajo, por lo que el predicado se puede serializar e inspeccionar sin depender de cierres.

repeat_while()

PHP
Queuety::workflow( 'poll_remote_status' )
    ->max_transitions( 20 )
    ->then( PollRemoteStatusStep::class, 'poll' )
    ->delay( seconds: 30 )
    ->repeat_while( 'poll', 'should_poll_again', true, 'repeat_poll' )
    ->then( FinalizeImportStep::class )
    ->dispatch( [ 'import_id' => 99 ] );

Este patrón resulta útil cuando un paso escribe un valor booleano sencillo como should_poll_again, has_more_pages o needs_revision.

Por qué las repeticiones están separadas de _next_step

Aún puedes crear ramas manualmente devolviendo _next_step desde un paso normal. Las funciones auxiliares de repetición están pensadas para el caso más concreto en que:

  • el destino es un paso anterior
  • la condición procede del estado público del flujo de trabajo
  • quieres que la lógica de repetición siga visible en la definición del flujo de trabajo

Así resulta más fácil inspeccionar las repeticiones en las exportaciones, los registros de eventos y la documentación que si la conexión de retorno queda oculta en código arbitrario de un paso.

Cómo limitar las repeticiones

Usa max_iterations cuando quieras establecer un límite estricto para una repetición concreta:

PHP
Queuety::workflow( 'poll_remote_status' )
    ->then( PollRemoteStatusStep::class, 'poll' )
    ->repeat_while( 'poll', 'should_poll_again', true, max_iterations: 8 )
    ->dispatch();

Usa max_transitions() cuando necesites un mecanismo más amplio para detener todo el flujo de trabajo:

PHP
Queuety::workflow( 'safe_revision_loop' )
    ->max_transitions( 10 )
    ->then( DraftBriefStep::class, 'draft' )
    ->wait_for_decision( result_key: 'review' )
    ->then( NormalizeReviewOutcomeStep::class )
    ->repeat_until( 'draft', 'review_approved', true )
    ->dispatch();

Si una repetición supera max_iterations o el flujo de trabajo supera max_transitions(), Queuety marca la ejecución como fallida en vez de dejarla en un bucle infinito.