
# Ponovitve

Queuety so urejene verige korakov. Z nadzornim korakom ponavljanja se vrnite na prej poimenovani korak, namesto da ročno pišete logiko `_next_step`.

Izberite obliko, ki ustreza poteku dela:

- javni `state_key`, kadar je pogoj preprost
- `condition_class`, kadar ponovitev zahteva naprednejšo logiko
- `max_iterations`, kadar mora imeti sama ponovitev strogo omejitev

Obe metodi ciljata na prej poimenovani korak, zato je ponovitev mogoče serializirati in znova predvajati, nadzoruje pa jo isto izvajalno okolje poteka dela kot vsak drug korak.

Pogoj ponovitve se ovrednoti na podlagi trajno shranjenega javnega stanja poteka dela, ko se predhodni korak zaključi, zato vsaka iteracija ostane ohranjena tudi ob ponovnem zagonu izvajalnika.

## `repeat_until()` s ključem stanja

```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` lahko poenostavi podatke odločitve v preprost javni ključ:

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

Če `review_approved` še vedno ni `true`, korak ponovitve skoči nazaj na `draft`. Ko postane `true`, potek dela nadaljuje z `PublishBriefStep`.

Signali se shranijo, ne porabijo. Ob drugem prehodu skozi `wait_for_decision()` se prejšnji signal `rejected` še vedno ujema in čakanje se takoj konča, zato bi se zanka vrtela, dokler je ne ustavi `max_transitions()`. Vsakemu krogu dodelite svoj ključ: poskrbite, da `DraftBriefStep` vrne naraščajoči `review_round`, posredujte `correlation_key: 'review_round'` v `wait_for_decision()`, pregledovalec pa naj v koristnem podatkovnem delu signala pošlje isti `review_round`. Čakanje se nato konča le, če je `review_round` signala enak trenutni vrednosti stanja.

## `repeat_until()` s pogojnim razredom

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

Pogojni razredi prejmejo javno stanje poteka dela, zato je predikat mogoče serializirati in pregledati brez odvisnosti od zaprtij.

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

Ta vzorec je uporaben, kadar korak zapiše preprosto logično vrednost, kot je `should_poll_again`, `has_more_pages` ali `needs_revision`.

## Zakaj so ponovitve ločene od `_next_step`

Še vedno lahko ročno razvejite potek dela tako, da običajen korak vrne `_next_step`. Pomožne funkcije za ponavljanje so namenjene ožjemu primeru, ko:

- je cilj prejšnji korak
- pogoj izhaja iz javnega stanja poteka dela
- želite, da je logika ponavljanja vidna že v sami definiciji poteka dela

Tako je ponovitve lažje pregledati v izvozih, dnevnikih dogodkov in dokumentaciji, kot če povratno povezavo skrijete v poljubni kodi koraka.

## Omejevanje ponovitev

Uporabite `max_iterations`, kadar potrebujete lokalno strogo omejitev za določeno ponovitev:

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

Uporabite `max_transitions()`, kadar potrebuje širšo varovalko celoten potek dela:

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

Če ponovitev preseže `max_iterations` ali potek dela preseže `max_transitions()`, Queuety prekine izvajanje, namesto da bi se ta neskončno vrtel.

## Povezana dokumentacija

- [Pogojno razvejanje](https://queuety.inline0.dev/sl/docs/workflows/conditional)
- [Signali](https://queuety.inline0.dev/sl/docs/workflows/signals)
- [Varovala](https://queuety.inline0.dev/sl/docs/workflows/guardrails)
- [PHP API](https://queuety.inline0.dev/sl/docs/api)
