Перейти до вмісту

Повтори

Queuety робочих процесів — це впорядковані ланцюжки кроків. Використовуйте керувальний крок повторення, щоб повернутися до попереднього іменованого кроку, замість того щоб вручну писати логіку _next_step.

Виберіть форму, яка відповідає робочому процесу:

  • публічний state_key, якщо умова проста
  • condition_class, якщо для повтору потрібна складніша логіка
  • max_iterations, якщо для самого повтору потрібна жорстка межа

Обидва методи спрямовують виконання до попереднього іменованого кроку, тому повтор залишається серіалізованим і відтворюваним та обмежується тим самим середовищем виконання робочого процесу, що й усі інші кроки.

Умова повтору перевіряється за збереженим публічним станом робочого процесу після завершення попереднього кроку, тому кожна ітерація зберігається навіть після перезапуску виконавця.

repeat_until() із ключем стану

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 може звести дані для рішення до простого публічного ключа:

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

Якщо 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() із класом умови

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

Класи умов отримують публічний стан робочого процесу, тому предикат залишається серіалізованим і придатним для перевірки без залежності від замикань.

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

Цей шаблон корисний, коли крок записує просте логічне значення, наприклад should_poll_again, has_more_pages або needs_revision.

Чому повтори відокремлені від _next_step

Ви й далі можете виконувати розгалуження вручну, повертаючи _next_step зі звичайного кроку. Допоміжні засоби повторення призначені для вужчого випадку, коли:

  • ціль — попередній крок
  • умова визначається з публічного стану робочого процесу
  • ви хочете, щоб логіка повторення залишалася видимою безпосередньо у визначенні робочого процесу

Завдяки цьому повтори легше перевіряти в експортах, журналах подій і документації, ніж логіку повернення, приховану в довільному коді кроку.

Обмеження повторів

Використовуйте max_iterations, коли потрібно встановити локальну жорстку межу для конкретного повтору:

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

Використовуйте max_transitions(), коли для всього робочого процесу потрібен ширший запобіжник:

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

Якщо повтор перевищує max_iterations або робочий процес перевищує max_transitions(), Queuety завершує запуск із помилкою, не дозволяючи йому тривати нескінченно.