
# Atkārtojumi

Queuety darbplūsmas ir sakārtotas darbību ķēdes. Izmantojiet atkārtošanas vadības darbību, lai atgrieztos pie agrākas nosauktas darbības, nevis rakstītu `_next_step` loģiku manuāli.

Izvēlieties darbplūsmai piemērotāko formu:

- publisku `state_key`, ja nosacījums ir vienkāršs
- `condition_class`, ja atkārtošanai vajadzīga sarežģītāka loģika
- `max_iterations`, ja atkārtošanai nepieciešama stingra robeža

Abas metodes norāda uz agrāku nosauktu darbību, tāpēc atkārtojums paliek serializējams, atkārtojami izpildāms un to pārvalda tā pati darbplūsmas izpildlaika vide kā visas pārējās darbības.

Atkārtošanas nosacījums tiek pārbaudīts saglabātajā publiskajā darbplūsmas stāvoklī pēc iepriekšējās darbības pabeigšanas, tāpēc katra iterācija saglabājas arī pēc darbinieka restartēšanas.

## `repeat_until()` ar stāvokļa atslēgu

```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` var pārveidot lēmuma datus vienkāršā publiskā atslēgā:

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

Ja `review_approved` joprojām nav `true`, atkārtošanas darbība pāriet atpakaļ uz `draft`. Kad tas kļūst par `true`, darbplūsma turpina izpildi ar `PublishBriefStep`.

Signāli tiek saglabāti, nevis patērēti. Otrajā reizē, kad tiek izpildīts `wait_for_decision()`, iepriekšējais signāls `rejected` joprojām atbilst nosacījumam, un gaidīšana tiek pabeigta uzreiz, tāpēc cikls atkārtotos, līdz `max_transitions()` to apturētu. Katram ciklam piešķiriet savu atslēgu: lieciet `DraftBriefStep` atgriezt pieaugošu `review_round`, nododiet `correlation_key: 'review_round'` uz `wait_for_decision()` un lieciet pārskatītājam signāla datos nosūtīt to pašu `review_round`. Tad gaidīšanu pabeigs tikai tāds signāls, kura `review_round` vērtība sakrīt ar pašreizējo stāvokļa vērtību.

## `repeat_until()` ar nosacījuma klasi

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

Nosacījuma klases saņem publisko darbplūsmas stāvokli, tāpēc predikāts paliek serializējams un pārbaudāms, nepaļaujoties uz slēgumiem.

## `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 paraugs noder, ja darbība ieraksta vienkāršu Būla vērtību, piemēram, `should_poll_again`, `has_more_pages` vai `needs_revision`.

## Kāpēc atkārtojumi ir nodalīti no `_next_step`

Joprojām varat veidot atzarojumus manuāli, parastā darbībā atgriežot `_next_step`. Atkārtojumu palīgmetodes paredzētas šaurākam lietojumam, kad:

- mērķis ir iepriekšēja darbība
- nosacījums izriet no publiskā darbplūsmas stāvokļa
- vēlaties, lai atkārtojuma loģika būtu redzama pašā darbplūsmas definīcijā

Tāpēc atkārtojumus ir vieglāk pārbaudīt eksportētajos datos, notikumu žurnālos un dokumentācijā, nekā paslēpjot atpakaļsaiti patvaļīgā darbības kodā.

## Atkārtojumu ierobežošana

Izmantojiet `max_iterations`, ja konkrētam atkārtojumam nepieciešama lokāla stingra robeža:

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

Izmantojiet `max_transitions()`, ja visai darbplūsmai nepieciešams plašāks avārijas apturēšanas slēdzis:

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

Ja atkārtojums pārsniedz `max_iterations` vai darbplūsma pārsniedz `max_transitions()`, Queuety pārtrauc izpildi, neļaujot tai griezties bezgalīgi.

## Saistītā dokumentācija

- [Nosacījumu atzarojumi](https://queuety.inline0.dev/lv/docs/workflows/conditional)
- [Signāli](https://queuety.inline0.dev/lv/docs/workflows/signals)
- [Aizsardzības ierobežojumi](https://queuety.inline0.dev/lv/docs/workflows/guardrails)
- [PHP API](https://queuety.inline0.dev/lv/docs/api)
