Повторения
Queuety Рабочие процессы представляют собой упорядоченные цепочки шагов. Используйте управляющий шаг повтора, чтобы вернуться к предыдущему именованному шагу, вместо того чтобы вручную писать логику _next_step.
Выберите подходящий для рабочего процесса вариант:
- общедоступный
state_key, если условие простое condition_class, если для повтора требуется более сложная логикаmax_iterations, если самому повтору нужен жесткий предел
Оба метода указывают на предыдущий именованный шаг, поэтому повтор можно сериализовать и воспроизводить, а среда выполнения рабочего процесса применяет к нему те же ограничения, что и к любому другому шагу.
Условие повтора проверяется по сохраненному общедоступному состоянию рабочего процесса после завершения предыдущего шага, поэтому каждая итерация сохраняется при перезапусках исполнителя.
repeat_until() с ключом состояния
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 может свести полезную нагрузку решения к простому общедоступному ключу:
class NormalizeReviewOutcomeStep implements \Queuety\Step {
public function handle( array $state ): array {
return [
'review_approved' => 'approved' === ( $state['review']['outcome'] ?? null ),
];
}
public function config(): array {
return [];
}
}
Если review_approved по-прежнему не true, шаг повтора возвращается к draft. Когда оно становится true, рабочий процесс переходит к PublishBriefStep.
Сигналы сохраняются, а не потребляются. При втором прохождении через wait_for_decision() прежний сигнал rejected по-прежнему подходит, и ожидание завершается немедленно, поэтому цикл будет повторяться, пока его не остановит max_transitions(). Используйте для каждого раунда свой ключ: пусть DraftBriefStep возвращает возрастающее значение review_round, передавайте correlation_key: 'review_round' в wait_for_decision(), а проверяющий отправляет то же review_round в полезной нагрузке сигнала. Тогда ожидание завершится только для сигнала, у которого review_round совпадает с текущим значением состояния.
repeat_until() с классом условия
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 );
}
}
Классы условий получают общедоступное состояние рабочего процесса, поэтому предикат можно сериализовать и анализировать без замыканий.
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 ] );
Этот шаблон полезен, когда шаг записывает простое логическое значение, например should_poll_again, has_more_pages или needs_revision.
Почему повторы отделены от _next_step
Вы по-прежнему можете создавать ветвления вручную, возвращая _next_step из обычного шага. Вспомогательные средства повтора предназначены для более узкого случая, когда:
- цель — предыдущий шаг
- условие берется из общедоступного состояния рабочего процесса
- нужно, чтобы логика повтора оставалась видимой в самом определении рабочего процесса
Так повторы проще анализировать в экспортах, журналах событий и документации, чем если бы возврат к предыдущему шагу был спрятан в произвольном коде шага.
Ограничение повторов
Используйте max_iterations, если для конкретного повтора нужен локальный жесткий предел:
Queuety::workflow( 'poll_remote_status' )
->then( PollRemoteStatusStep::class, 'poll' )
->repeat_while( 'poll', 'should_poll_again', true, max_iterations: 8 )
->dispatch();
Используйте max_transitions(), если всему рабочему процессу нужен более общий механизм аварийного останова:
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();
Если повтор превышает max_iterations или рабочий процесс превышает max_transitions(), Queuety завершает запуск с ошибкой, не позволяя ему выполняться бесконечно.