For-Each dinâmico
Use ->for_each() quando o fluxo de trabalho não souber a quantidade de ramificações no momento da criação. Queuety lê um array do estado do fluxo de trabalho, despacha um trabalho de ramificação para cada item e avança somente quando a condição de conclusão configurada é atendida.
O método ->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 ] );
A etapa planejadora grava pages no estado do fluxo de trabalho. A etapa for-each lê esse array e despacha um trabalho de ramificação para cada item.
Manipuladores de ramificação
Os manipuladores de ramificação for-each implementam 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',
];
}
}
Em config(), backoff recebe um nome de estratégia: exponential, linear ou fixed. Uma lista de atrasos por tentativa nesse local é descartada atualmente, causando novas tentativas imediatas (#16); em vez disso, defina os atrasos por tentativa em backoff da definição da etapa.
$state contém o estado completo do fluxo de trabalho, $item é o item individual do for-each e $index é sua posição baseada em zero.
Modos de conclusão
ForEachMode::All
A etapa só é concluída depois que todas as ramificações são bem-sucedidas. Qualquer falha permanente em uma ramificação faz a etapa for-each falhar.
ForEachMode::FirstSuccess
A etapa é concluída assim que a primeira ramificação tem sucesso. As ramificações ativas restantes são marcadas como substituídas.
ForEachMode::Quorum
A etapa é concluída quando pelo menos quorum ramificações têm sucesso. Se as ramificações restantes já não puderem atingir o quórum, o fluxo de trabalho falha.
Redutores
Por padrão, Queuety armazena um agregado estruturado em result_key:
modequorumtotalsucceededfailedsettledwinnerresultsfailures
Para criar um resumo personalizado, passe uma classe redutora que implemente Contracts\ForEachReducer. O agregado continua armazenado em result_key, e as chaves retornadas pelo redutor são mescladas ao estado do fluxo de trabalho ao lado dele:
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,
];
}
}
A saída do redutor é mesclada ao estado do fluxo de trabalho como qualquer outra saída de etapa. Ele também pode retornar _next_step para ramificar após a conclusão do for-each.
Comportamento de novas tentativas
As ramificações for-each fazem novas tentativas de forma independente, de acordo com config() do manipulador da ramificação. Se a etapa for-each falhar e você chamar retry_workflow(), Queuety expande a etapa for-each novamente e coloca em fila apenas as ramificações ainda ausentes ou com falha. Os resultados das ramificações bem-sucedidas permanecem no estado do fluxo de trabalho.
Escolher entre parallel() e for_each()
Use parallel() quando a lista de ramificações estiver fixa no código.
Use for_each() quando a lista de ramificações for descoberta em tempo de execução a partir do estado do fluxo de trabalho e você precisar de modos de conclusão como primeira ramificação bem-sucedida ou quórum.