Przejdź do treści

Powtórzenia

Queuety workflows to uporządkowane ciągi kroków. Użyj kroku sterującego powtórzeniem, aby wrócić do wcześniejszego nazwanego kroku, zamiast ręcznie pisać logikę _next_step.

Wybierz formę pasującą do workflow:

  • publiczne state_key, gdy warunek jest prosty
  • condition_class, gdy powtórzenie wymaga bardziej rozbudowanej logiki
  • max_iterations, gdy samo powtórzenie wymaga twardego limitu

Obie metody wskazują wcześniejszy nazwany krok, dzięki czemu powtórzenie pozostaje serializowalne, możliwe do odtworzenia i objęte tym samym środowiskiem wykonawczym workflow co każdy inny krok.

Warunek powtórzenia jest sprawdzany na podstawie utrwalonego publicznego stanu workflow po zakończeniu poprzedzającego kroku, dzięki czemu każda iteracja jest odporna na ponowne uruchomienie workera.

repeat_until() z kluczem stanu

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 może spłaszczyć dane decyzyjne do prostego klucza publicznego:

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 [];
    }
}

Jeśli review_approved nadal nie jest true, krok powtórzenia wraca do draft. Gdy stanie się true, workflow przechodzi dalej do PublishBriefStep.

Sygnały są zapisywane, a nie zużywane. Przy drugim przejściu przez wait_for_decision() wcześniejszy sygnał rejected nadal pasuje, a oczekiwanie kończy się natychmiast, więc pętla działałaby bez końca, dopóki nie zatrzymałoby jej max_transitions(). Nadaj każdej rundzie własny klucz: niech DraftBriefStep zwraca rosnącą wartość review_round, przekaż correlation_key: 'review_round' do wait_for_decision() i poproś recenzenta o wysłanie tej samej wartości review_round w danych sygnału. Oczekiwanie kończy wtedy tylko sygnał, którego review_round jest równe bieżącej wartości stanu.

repeat_until() z klasą warunku

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 );
    }
}

Klasy warunków otrzymują publiczny stan workflow, dzięki czemu predykat pozostaje serializowalny i możliwy do sprawdzenia bez polegania na domknięciach.

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 ] );

Ten wzorzec przydaje się, gdy krok zapisuje prostą wartość logiczną, taką jak should_poll_again, has_more_pages lub needs_revision.

Dlaczego powtórzenia są oddzielone od _next_step

Nadal możesz ręcznie rozgałęziać workflow, zwracając _next_step ze zwykłego kroku. Pomocnicze mechanizmy powtórzeń służą węższemu przypadkowi, gdy:

  • celem jest wcześniejszy krok
  • warunek pochodzi z publicznego stanu workflow
  • chcesz, aby logika powtórzenia była widoczna bezpośrednio w definicji workflow

Dzięki temu powtórzenia łatwiej sprawdzać w eksportach, dziennikach zdarzeń i dokumentacji niż w przypadku ukrycia krawędzi powrotnej w dowolnym kodzie kroku.

Zabezpieczanie powtórzeń

Użyj max_iterations, gdy konkretne powtórzenie wymaga własnego twardego limitu:

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

Użyj max_transitions(), gdy cały workflow wymaga szerszego wyłącznika awaryjnego:

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();

Jeśli powtórzenie przekroczy max_iterations lub workflow przekroczy max_transitions(), Queuety zakończy przebieg niepowodzeniem, zamiast pozwolić mu działać bez końca.