Repetări
Queuety fluxurile de lucru sunt lanțuri ordonate de pași. Folosiți un pas de control al repetării pentru a reveni la un pas anterior cu nume, în loc să scrieți manual logica _next_step.
Alegeți forma potrivită pentru fluxul de lucru:
- un
state_keypublic când condiția este simplă - o
condition_classcând repetarea necesită o logică mai complexă max_iterationscând repetarea în sine are nevoie de o limită strictă
Ambele metode vizează un pas anterior cu nume, astfel încât repetarea rămâne serializabilă, reexecutabilă și protejată de același motor de fluxuri de lucru ca orice alt pas.
Condiția de repetare este evaluată pe baza stării publice persistate a fluxului de lucru după încheierea pasului precedent, astfel încât fiecare iterație rezistă la repornirea lucrătorului.
repeat_until() cu o cheie de stare
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 poate aplatiza datele deciziei într-o cheie publică simplă:
class NormalizeReviewOutcomeStep implements \Queuety\Step {
public function handle( array $state ): array {
return [
'review_approved' => 'approved' === ( $state['review']['outcome'] ?? null ),
];
}
public function config(): array {
return [];
}
}
Dacă review_approved încă nu este true, pasul de repetare revine la draft. Când devine true, fluxul de lucru trece la PublishBriefStep.
Semnalele sunt stocate, nu consumate. La a doua trecere prin wait_for_decision(), semnalul rejected anterior se potrivește în continuare, iar așteptarea se încheie imediat, astfel încât bucla s-ar repeta la nesfârșit până când max_transitions() o oprește. Dați fiecărei runde propria cheie: faceți ca DraftBriefStep să returneze un review_round incrementat, transmiteți correlation_key: 'review_round' către wait_for_decision() și solicitați evaluatorului să trimită aceeași review_round în datele utile ale semnalului. Așteptarea se încheie apoi numai dacă review_round semnalului este egală cu valoarea curentă a stării.
repeat_until() cu o clasă de condiție
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 );
}
}
Clasele de condiție primesc starea publică a fluxului de lucru, astfel încât predicatul rămâne serializabil și inspectabil fără a depinde de închideri.
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 ] );
Acest tipar este util când un pas scrie o valoare booleană simplă, cum ar fi should_poll_again, has_more_pages sau needs_revision.
De ce repetările sunt separate de _next_step
Puteți ramifica în continuare manual returnând _next_step dintr-un pas obișnuit. Funcțiile auxiliare de repetare sunt pentru cazul mai restrâns în care:
- ținta este un pas anterior
- condiția provine din starea publică a fluxului de lucru
- doriți ca logica de repetare să rămână vizibilă chiar în definiția fluxului de lucru
Astfel, repetările sunt mai ușor de inspectat în exporturi, jurnalele de evenimente și documentație decât dacă ascundeți bucla de revenire în cod arbitrar al unui pas.
Protejarea repetărilor
Folosiți max_iterations când o anumită repetare are nevoie de o limită strictă locală:
Queuety::workflow( 'poll_remote_status' )
->then( PollRemoteStatusStep::class, 'poll' )
->repeat_while( 'poll', 'should_poll_again', true, max_iterations: 8 )
->dispatch();
Folosiți max_transitions() când întregul flux de lucru are nevoie de un mecanism general de oprire de urgență:
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();
Dacă o repetare depășește max_iterations sau fluxul de lucru depășește max_transitions(), Queuety oprește execuția cu eroare, în loc să o lase să se repete la nesfârșit.