Wiederholungen
Queuety-Workflows sind geordnete Schrittketten. Mit einem Wiederholungssteuerungsschritt kannst du zu einem früheren benannten Schritt zurückkehren, statt _next_step-Logik von Hand zu schreiben.
Wähle die passende Form für deinen Workflow:
- ein öffentliches
state_keybei einfachen Bedingungen - ein
condition_class, wenn die Wiederholung komplexere Logik erfordert max_iterations, wenn die Wiederholung selbst unbedingt beendet werden muss
Beide Methoden zielen auf einen früheren benannten Schritt. So bleibt die Wiederholung serialisierbar und erneut abspielbar und wird wie jeder andere Schritt durch dieselbe Workflow-Laufzeitumgebung abgesichert.
Die Wiederholungsbedingung wird nach Abschluss des vorhergehenden Schritts anhand des persistenten öffentlichen Workflow-Status ausgewertet. Dadurch bleibt jede Iteration auch nach einem Neustart des Workers dauerhaft erhalten.
repeat_until() mit einem Statusschlüssel
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 kann die Entscheidungsdaten in einen einfachen öffentlichen Schlüssel übertragen:
class NormalizeReviewOutcomeStep implements \Queuety\Step {
public function handle( array $state ): array {
return [
'review_approved' => 'approved' === ( $state['review']['outcome'] ?? null ),
];
}
public function config(): array {
return [];
}
}
Ist review_approved weiterhin nicht true, springt der Wiederholungsschritt zurück zu draft. Sobald der Wert true ist, fährt der Workflow mit PublishBriefStep fort.
Signale werden gespeichert, nicht verbraucht. Beim zweiten Durchlauf von wait_for_decision() stimmt das frühere Signal weiterhin mit rejected überein und beendet die Wartezeit sofort, sodass die Schleife laufen würde, bis max_transitions() sie stoppt. Verwende für jede Runde einen eigenen Schlüssel: Lass DraftBriefStep einen fortlaufenden review_round zurückgeben, übergib correlation_key: 'review_round' an wait_for_decision() und lass den Reviewer denselben review_round in der Signalnutzlast senden. Nur ein Signal, dessen review_round dem aktuellen Statuswert entspricht, beendet dann die Wartezeit.
repeat_until() mit einer Bedingungsklasse
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 );
}
}
Bedingungsklassen erhalten den öffentlichen Workflow-Status. So bleibt das Prädikat serialisierbar und prüfbar, ohne von Closures abhängig zu sein.
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 ] );
Dieses Muster ist nützlich, wenn ein Schritt einen einfachen booleschen Wert wie should_poll_again, has_more_pages oder needs_revision schreibt.
Warum Wiederholungen von _next_step getrennt sind
Du kannst weiterhin manuell verzweigen, indem du _next_step aus einem normalen Schritt zurückgibst. Die Wiederholungshelfer sind für den engeren Anwendungsfall gedacht, wenn:
- das Ziel ein vorheriger Schritt ist
- die Bedingung aus dem öffentlich zugänglichen Workflow-Zustand stammt
- die Wiederholungslogik direkt in der Workflow-Definition sichtbar bleiben soll
Dadurch lassen sich Wiederholungen in Exporten, Ereignisprotokollen und der Dokumentation leichter nachvollziehen, als wenn die Rückkante in beliebigem Schrittcode verborgen ist.
Wiederholungen absichern
Verwende max_iterations, wenn eine bestimmte Wiederholung eine lokale harte Grenze braucht:
Queuety::workflow( 'poll_remote_status' )
->then( PollRemoteStatusStep::class, 'poll' )
->repeat_while( 'poll', 'should_poll_again', true, max_iterations: 8 )
->dispatch();
Verwende max_transitions(), wenn der gesamte Workflow einen übergreifenden Notausschalter braucht:
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();
Wenn eine Wiederholung max_iterations überschreitet oder der Workflow max_transitions() überschreitet, schlägt Queuety den Lauf fehl, statt ihn endlos weiterlaufen zu lassen.