Repetições
Queuety Os fluxos de trabalho são cadeias ordenadas de etapas. Use uma etapa de controle de repetição para voltar a uma etapa nomeada anterior, em vez de escrever a lógica _next_step manualmente.
Escolha a forma que corresponde ao fluxo de trabalho:
- um
state_keypúblico quando a condição é simples - uma
condition_classquando a repetição exige uma lógica mais elaborada max_iterationsquando a própria repetição precisa de um limite rígido
Ambos os métodos apontam para uma etapa nomeada anterior, portanto a repetição continua serializável, reproduzível e protegida pelo mesmo ambiente de execução do fluxo de trabalho que todas as outras etapas.
A condição de repetição é avaliada a partir do estado público persistido do fluxo de trabalho após a conclusão da etapa anterior, mantendo cada iteração durável mesmo após reinicializações do worker.
repeat_until() com uma chave de estado
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 pode simplificar os dados de decisão em uma chave pública simples:
class NormalizeReviewOutcomeStep implements \Queuety\Step {
public function handle( array $state ): array {
return [
'review_approved' => 'approved' === ( $state['review']['outcome'] ?? null ),
];
}
public function config(): array {
return [];
}
}
Se review_approved ainda não for true, a etapa de repetição volta para draft. Quando se tornar true, o fluxo de trabalho continua para PublishBriefStep.
Os sinais são armazenados, não consumidos. Na segunda passagem por wait_for_decision(), o sinal rejected anterior ainda corresponde e a espera é concluída imediatamente, fazendo o loop continuar indefinidamente até que max_transitions() o interrompa. Use uma chave diferente a cada rodada: faça DraftBriefStep retornar um review_round incremental, passe correlation_key: 'review_round' para wait_for_decision() e peça ao revisor que envie o mesmo review_round no conteúdo do sinal. Assim, somente um sinal cujo review_round corresponda ao valor atual do estado concluirá a espera.
repeat_until() com uma classe de condição
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 );
}
}
As classes de condição recebem o estado público do fluxo de trabalho, mantendo o predicado serializável e inspecionável sem depender de closures.
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 ] );
Esse padrão é útil quando uma etapa grava um valor booleano simples, como should_poll_again, has_more_pages ou needs_revision.
Por que as repetições são separadas de _next_step
Você ainda pode criar ramificações manualmente retornando _next_step de uma etapa normal. Os auxiliares de repetição existem para o caso mais específico em que:
- o destino é uma etapa anterior
- a condição vem do estado público do fluxo de trabalho
- você quer que a lógica de repetição permaneça visível na própria definição do fluxo de trabalho
Isso facilita a inspeção das repetições em exportações, registros de eventos e documentação, em vez de ocultar o retorno dentro de um código de etapa arbitrário.
Como proteger as repetições
Use max_iterations quando uma repetição específica precisar de um limite rígido local:
Queuety::workflow( 'poll_remote_status' )
->then( PollRemoteStatusStep::class, 'poll' )
->repeat_while( 'poll', 'should_poll_again', true, max_iterations: 8 )
->dispatch();
Use max_transitions() quando todo o fluxo de trabalho precisar de um mecanismo geral de interrupção:
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();
Se uma repetição exceder max_iterations ou o fluxo de trabalho exceder max_transitions(), Queuety interromperá a execução em vez de permitir que ela continue indefinidamente.