
# Kartojimai

Queuety darbo sekos yra nuoseklios veiksmų grandinės. Naudokite kartojimo valdymo veiksmą, kad grįžtumėte prie ankstesnio pavadinto veiksmo, užuot rankiniu būdu rašę `_next_step` logiką.

Pasirinkite darbo sekai tinkamą formą:

- viešas `state_key`, kai sąlyga paprasta
- `condition_class`, kai kartojimui reikia sudėtingesnės logikos
- `max_iterations`, kai pačiam kartojimui reikia griežtos ribos

Abu metodai nurodo ankstesnį pavadintą veiksmą, todėl kartojimą galima serializuoti ir atkurti, o jį valdo ta pati darbo sekos vykdymo aplinka kaip ir kiekvieną kitą veiksmą.

Kartojimo sąlyga tikrinama pagal išsaugotą viešą darbo sekos būseną, kai baigiamas ankstesnis veiksmas, todėl kiekviena iteracija išlieka patikima ir paleidus darbuotoją iš naujo.

## `repeat_until()` su būsenos raktu

```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` gali pateikti sprendimo duomenis kaip paprastą viešą raktą:

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

Jei `review_approved` vis dar nėra `true`, kartojimo veiksmas grįžta prie `draft`. Kai jis tampa `true`, darbo seka tęsiasi nuo `PublishBriefStep`.

Signalai išsaugomi, o ne sunaudojami. Antrą kartą vykdant `wait_for_decision()`, ankstesnis signalas `rejected` vis dar atitinka sąlygą, todėl laukimas baigiasi iškart, o ciklas suktųsi tol, kol jo nesustabdytų `max_transitions()`. Kiekvienam ciklui suteikite atskirą raktą: pasirūpinkite, kad `DraftBriefStep` grąžintų didėjančią `review_round` reikšmę, perduokite `correlation_key: 'review_round'` į `wait_for_decision()`, o peržiūrą atliekantis asmuo signalo duomenyse pateiktų tą patį `review_round`. Tada laukimas baigsis tik tada, kai signalo `review_round` sutaps su dabartine būsenos reikšme.

## `repeat_until()` su sąlygos klase

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

Sąlygų klasės gauna viešą darbo sekos būseną, todėl predikatą galima serializuoti ir tikrinti nepasikliaujant uždaromis funkcijomis.

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

Šis šablonas naudingas, kai veiksmas įrašo paprastą loginę reikšmę, pavyzdžiui, `should_poll_again`, `has_more_pages` arba `needs_revision`.

## Kodėl kartojimai atskirti nuo `_next_step`

Vis dar galite šakotis rankiniu būdu, įprastame veiksme grąžindami `_next_step`. Kartojimo pagalbinės funkcijos skirtos siauresniam atvejui, kai:

- tikslas yra ankstesnis veiksmas
- sąlyga nustatoma pagal viešą darbo sekos būseną
- norite, kad kartojimo logika būtų matoma pačiame darbo sekos apraše

Taip kartojimus lengviau tikrinti eksportuotuose duomenyse, įvykių žurnaluose ir dokumentacijoje, nei paslėpus grįžtamąją nuorodą savavališkame veiksmo kode.

## Kartojimų ribojimas

Naudokite `max_iterations`, kai reikia griežtai apriboti vieną konkretų kartojimą:

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

Naudokite `max_transitions()`, kai visai darbo sekai reikia platesnio apsauginio jungiklio:

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

Jei kartojimas viršija `max_iterations` arba darbo seka viršija `max_transitions()`, Queuety nutraukia vykdymą, kad jis nesitęstų be galo.

## Susijusi dokumentacija

- [Sąlyginis šakojimas](https://queuety.inline0.dev/lt/docs/workflows/conditional)
- [Signalai](https://queuety.inline0.dev/lt/docs/workflows/signals)
- [Apsauginės priemonės](https://queuety.inline0.dev/lt/docs/workflows/guardrails)
- [PHP API](https://queuety.inline0.dev/lt/docs/api)
