Dynamische For-Each-Schritte
Verwende ->for_each(), wenn die Anzahl der Zweige zum Erstellungszeitpunkt des Workflows noch unbekannt ist. Queuety liest ein Array aus dem Workflow-Status, stellt pro Element einen Zweig-Job ein und fährt erst fort, wenn die konfigurierte Abschlussbedingung erfüllt ist.
Die Methode ->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 ] );
Der Planungsschritt schreibt pages in den Workflow-Status. Der For-Each-Schritt liest dieses Array und stellt pro Element einen Zweig-Job ein.
Handler für Zweige
Handler für For-Each-Zweige implementieren 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',
];
}
}
In config() übernimmt backoff einen Strategienamen: exponential, linear oder fixed. Eine Liste mit Verzögerungen pro Versuch wird dort derzeit verworfen, sodass Wiederholungen sofort erfolgen (#16). Lege Verzögerungen pro Versuch stattdessen in backoff der Schrittdefinition fest.
$state enthält den vollständigen Workflow-Status, $item ist das einzelne For-Each-Element und $index seine nullbasierte Position.
Abschlussmodi
ForEachMode::All
Der Schritt wird erst abgeschlossen, wenn alle Zweige erfolgreich sind. Jeder dauerhafte Fehler in einem Zweig lässt den For-Each-Schritt fehlschlagen.
ForEachMode::FirstSuccess
Der Schritt wird abgeschlossen, sobald der erste Zweig erfolgreich ist. Die übrigen aktiven Zweige werden als überholt markiert.
ForEachMode::Quorum
Der Schritt wird abgeschlossen, sobald mindestens quorum Zweige erfolgreich sind. Können die übrigen Zweige das Quorum nicht mehr erreichen, schlägt der Workflow fehl.
Reduzierer
Standardmäßig speichert Queuety unter result_key ein strukturiertes Gesamtergebnis:
modequorumtotalsucceededfailedsettledwinnerresultsfailures
Wenn du eine benutzerdefinierte Zusammenfassung möchtest, übergib eine Reducer-Klasse, die Contracts\ForEachReducer implementiert. Das Aggregat wird weiterhin unter result_key gespeichert, und die vom Reducer zurückgegebenen Schlüssel werden daneben mit dem Workflow-Status zusammengeführt:
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,
];
}
}
Die Ausgabe des Reducers wird wie die Ausgabe jedes anderen Schritts mit dem Workflow-Status zusammengeführt. Er kann auch _next_step zurückgeben, um nach Abschluss der For-each-Ausführung zu verzweigen.
Wiederholungsverhalten
For-each-Zweige werden gemäß dem config() des Zweighandlers unabhängig voneinander wiederholt. Wenn der For-each-Schritt fehlschlägt und du retry_workflow() aufrufst, entfaltet Queuety den For-each-Schritt erneut und reiht nur Zweige ein, die noch fehlen oder fehlgeschlagen sind. Erfolgreiche Zweigergebnisse bleiben im Workflow-Status erhalten.
parallel() und for_each() im Vergleich
Verwende parallel(), wenn die Zweigliste im Code festgelegt ist.
Verwende for_each(), wenn die Zweigliste zur Laufzeit anhand des Workflow-Status ermittelt wird und du Abschlussmodi wie erster Erfolg oder Quorum benötigst.