Répétitions
Queuety workflows sont des chaînes d’étapes ordonnées. Utilisez une étape de contrôle de répétition pour revenir à une étape nommée précédente, plutôt que d’écrire la logique _next_step à la main.
Choisissez la forme qui correspond au workflow :
- une
state_keypublique si la condition est simple - une
condition_classsi la répétition nécessite une logique plus élaborée max_iterationssi la répétition elle-même nécessite une limite stricte
Les deux méthodes ciblent une étape nommée antérieure : la répétition reste donc sérialisable, rejouable et soumise aux mêmes protections du moteur d’exécution que toutes les autres étapes.
La condition de répétition est évaluée à partir de l’état public persistant du workflow, une fois l’étape précédente terminée. Chaque itération reste ainsi durable même après le redémarrage des workers.
repeat_until() avec une clé d’état
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 peut réduire la charge utile de décision à une simple clé publique :
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 n’est toujours pas true, l’étape de répétition revient à draft. Dès qu’il devient true, le workflow passe à PublishBriefStep.
Les signaux sont stockés, pas consommés. Au deuxième passage par wait_for_decision(), le signal rejected précédent correspond toujours, et l’attente se termine aussitôt : la boucle tournerait donc jusqu’à ce que max_transitions() l’arrête. Attribuez une clé distincte à chaque tour : demandez à DraftBriefStep de renvoyer un review_round incrémenté, transmettez correlation_key: 'review_round' à wait_for_decision() et demandez à la personne chargée de la révision d’envoyer le même review_round dans la charge utile du signal. L’attente ne se termine alors que si le review_round du signal correspond à la valeur actuelle de l’état.
repeat_until() avec une classe de condition
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 ] );
namespace App\Workflows;
use Queuety\Contracts\RepeatCondition;
final class ReviewApprovedCondition implements RepeatCondition {
public function matches( array $state ): bool {
return 'approved' === ( $state['review']['outcome'] ?? null );
}
}
Les classes de condition reçoivent l’état public du workflow. Le prédicat reste ainsi sérialisable et inspectable, sans dépendre de fermetures.
repeat_while()
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 ] );
Ce modèle est utile lorsqu’une étape écrit une valeur booléenne simple, comme should_poll_again, has_more_pages ou needs_revision.
Pourquoi les répétitions sont distinctes de _next_step
Vous pouvez toujours créer des branches manuellement en renvoyant _next_step depuis une étape ordinaire. Les aides à la répétition sont prévues pour le cas plus précis où :
- la cible est une étape antérieure
- la condition provient de l’état public du workflow
- vous souhaitez que la logique de répétition reste visible dans la définition du workflow
Les répétitions sont ainsi plus faciles à examiner dans les exports, les journaux d’événements et la documentation que si le retour en arrière était enfoui dans du code d’étape arbitraire.
Encadrer les répétitions
Utilisez max_iterations lorsqu’une répétition précise nécessite une limite stricte locale :
Queuety::workflow( 'poll_remote_status' )
->then( PollRemoteStatusStep::class, 'poll' )
->repeat_while( 'poll', 'should_poll_again', true, max_iterations: 8 )
->dispatch();
Utilisez max_transitions() lorsque l’ensemble du workflow nécessite un mécanisme d’arrêt global :
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 une répétition dépasse max_iterations, ou si le workflow dépasse max_transitions(), Queuety interrompt l’exécution au lieu de la laisser tourner indéfiniment.