Zum Inhalt springen

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_key bei 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

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 kann die Entscheidungsdaten in einen einfachen öffentlichen Schlüssel übertragen:

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

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

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

Bedingungsklassen erhalten den öffentlichen Workflow-Status. So bleibt das Prädikat serialisierbar und prüfbar, ohne von Closures abhängig zu sein.

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

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:

PHP
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:

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

Wenn eine Wiederholung max_iterations überschreitet oder der Workflow max_transitions() überschreitet, schlägt Queuety den Lauf fehl, statt ihn endlos weiterlaufen zu lassen.