Динамічний цикл for-each
Використовуйте ->for_each(), коли кількість гілок процесу невідома під час його побудови. Queuety зчитує масив зі стану процесу, запускає окреме завдання гілки для кожного елемента й переходить далі, лише коли виконується налаштована умова завершення.
Метод ->for_each()
use Queuety\Contracts\ForEachHandler;
use Queuety\Contracts\ForEachReducer;
use Queuety\Enums\ForEachMode;
use Queuety\Queuety;
Queuety::workflow( 'index_site' )
->then( PlanPagesStep::class )
->for_each(
items_key: 'pages',
handler_class: IndexPageStep::class,
result_key: 'page_results',
mode: ForEachMode::Quorum,
quorum: 2,
reducer_class: IndexSummaryReducer::class,
name: 'index_pages',
)
->then( PublishIndexStep::class )
->dispatch( [ 'site_id' => 42 ] );
Крок планування записує pages у стан процесу. Крок for-each зчитує цей масив і запускає окреме завдання гілки для кожного елемента.
Обробники гілок
Обробники гілок for-each реалізують Contracts\ForEachHandler:
use Queuety\Contracts\ForEachHandler;
final class IndexPageStep implements ForEachHandler {
public function handle_item( array $state, mixed $item, int $index ): array {
$page = is_array( $item ) ? $item : [ 'url' => (string) $item ];
return [
'url' => $page['url'],
'title' => fetch_title( $page['url'] ),
'index' => $index,
];
}
public function config(): array {
return [
'max_attempts' => 3,
'backoff' => 'exponential',
];
}
}
У config() параметр backoff приймає назву стратегії: exponential, linear або fixed. Список затримок між спробами, заданий там, наразі відкидається й замінюється негайними повторними спробами (#16); задавайте затримки між спробами у визначенні кроку через backoff.
$state містить повний стан процесу, $item — окремий елемент циклу for-each, а $index — його позицію, починаючи з нуля.
Режими завершення
ForEachMode::All
Крок завершується, лише коли успішно виконано всі гілки. Будь-яка остаточна помилка гілки спричиняє помилку кроку for-each.
ForEachMode::FirstSuccess
Крок завершується, щойно успішно виконується перша гілка. Решта активних гілок позначаються як витіснені.
ForEachMode::Quorum
Крок завершується, коли успішно виконано щонайменше quorum гілок. Якщо решта гілок уже не можуть виконати цю умову, процес завершується помилкою.
Редуктори
За замовчуванням Queuety зберігає структурований зведений результат у result_key:
modequorumtotalsucceededfailedsettledwinnerresultsfailures
Якщо потрібен власний зведений результат, передайте клас редуктора, що реалізує Contracts\ForEachReducer. Зведений результат усе одно зберігається в result_key, а повернуті редуктором ключі об'єднуються зі станом процесу поруч із ним:
use Queuety\Contracts\ForEachReducer;
final class IndexSummaryReducer implements ForEachReducer {
public function reduce( array $state, array $for_each ): array {
return [
'indexed_count' => count( $for_each['results'] ),
'winning_url' => $for_each['winner']['output']['url'] ?? null,
];
}
}
Результат редуктора об'єднується зі станом процесу, як і результат будь-якого іншого кроку. Також він може повертати _next_step для розгалуження після завершення for-each.
Повторні спроби
Гілки for-each повторюються незалежно відповідно до config() обробника гілки. Якщо крок for-each завершується помилкою та ви викликаєте retry_workflow(), Queuety повторно розгортає крок for-each і ставить у чергу лише відсутні гілки або гілки з помилками. Результати успішних гілок залишаються у стані процесу.
Вибір між parallel() і for_each()
Використовуйте parallel(), коли список гілок визначено в коді.
Використовуйте for_each(), коли список гілок визначається під час виконання зі стану процесу й потрібні режими завершення на кшталт першого успіху або кворуму.