
# Ismétlések

A Queuety munkafolyamatok rendezett lépéssorok. Ismétlési vezérlőlépéssel visszatérhet egy korábbi, névvel ellátott lépéshez, így nem kell kézzel megírnia a `_next_step` logikát.

Válassza a munkafolyamathoz illő formát:

- egy nyilvános `state_key`, ha a feltétel egyszerű
- egy `condition_class`, ha az ismétlés összetettebb logikát igényel
- `max_iterations`, ha magának az ismétlésnek kell egyértelmű leállítási feltétel

Mindkét metódus egy korábbi, névvel ellátott lépést céloz meg, így az ismétlés szerializálható és visszajátszható marad, valamint ugyanaz a munkafolyamat-futtatókörnyezet felügyeli, mint az összes többi lépést.

Az ismétlési feltétel a megelőző lépés befejezése után, a tartósan tárolt nyilvános munkafolyamat-állapotból kerül kiértékelésre, így minden iteráció megőrzi tartósságát a feldolgozók újraindítása esetén is.

## `repeat_until()` állapotkulccsal

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

A `NormalizeReviewOutcomeStep` egyszerű, nyilvános kulccsá alakíthatja a döntési adatot:

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

Ha a `review_approved` továbbra sem `true`, az ismétlési lépés visszaugrik a `draft` lépéshez. Amint `true` lesz, a munkafolyamat a `PublishBriefStep` lépéssel folytatódik.

A jelek tárolódnak, nem használódnak fel. A `wait_for_decision()` második futásakor a korábbi `rejected` jel továbbra is illeszkedik, ezért a várakozás azonnal lezárul, és a ciklus addig pörögne, amíg a `max_transitions()` le nem állítja. Minden körhöz adjon külön kulcsot: a `DraftBriefStep` adjon vissza növekvő `review_round` értéket, ezt adja át a `wait_for_decision()` számára a `correlation_key: 'review_round'` segítségével, a felülvizsgáló pedig ugyanazt a `review_round` értéket küldje el a jel adatcsomagjában. Ekkor csak az a jel zárja le a várakozást, amelynek `review_round` értéke megegyezik az aktuális állapot értékével.

## `repeat_until()` feltételosztállyal

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

A feltételosztályok megkapják a nyilvános munkafolyamat-állapotot, így a predikátum szerializálható és ellenőrizhető marad, lezárásokra való támaszkodás nélkül.

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

Ez a minta akkor hasznos, ha egy lépés egyszerű logikai értéket, például `should_poll_again`, `has_more_pages` vagy `needs_revision` értéket ír be.

## Miért különállóak az ismétlések a `_next_step` lehetőségtől?

A kézi elágaztatás továbbra is lehetséges, ha egy normál lépésből `_next_step` értéket ad vissza. Az ismétlési segédmetódusok szűkebb esetre szolgálnak, amikor:

- a cél egy korábbi lépés
- a feltétel a nyilvános munkafolyamat-állapotból származik
- azt szeretné, hogy az ismétlés logikája magában a munkafolyamat definíciójában látható maradjon

Így az ismétlések könnyebben ellenőrizhetők az exportokban, eseménynaplókban és dokumentációban, mintha a visszaugrás tetszőleges lépéskódba lenne rejtve.

## Az ismétlések korlátozása

Használja a `max_iterations` lehetőséget, ha egy adott ismétléshez helyi, egyértelmű leállítási feltételre van szükség:

```php
Queuety::workflow( 'poll_remote_status' )
    ->then( PollRemoteStatusStep::class, 'poll' )
    ->repeat_while( 'poll', 'should_poll_again', true, max_iterations: 8 )
    ->dispatch();
```

Használja a `max_transitions()` lehetőséget, ha a teljes munkafolyamathoz átfogóbb biztonsági kapcsolóra van szükség:

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

Ha egy ismétlés túllépi a `max_iterations` értéket, vagy a munkafolyamat túllépi a `max_transitions()` értéket, a Queuety meghiúsítja a futást ahelyett, hogy végtelen ciklusba engedné.

## Kapcsolódó dokumentáció

- [Feltételes elágazás](https://queuety.inline0.dev/hu/docs/workflows/conditional)
- [Jelek](https://queuety.inline0.dev/hu/docs/workflows/signals)
- [Korlátok](https://queuety.inline0.dev/hu/docs/workflows/guardrails)
- [PHP API](https://queuety.inline0.dev/hu/docs/api)
