
# Zależności przepływów pracy

Użyj oczekiwania na zależności przepływów pracy, gdy przepływ najwyższego poziomu powinien kontynuować działanie dopiero po zakończeniu innych przepływów. Pozwala to koordynować wiele przepływów pracy bez umieszczania wszystkiego w jednej ogromnej definicji.

Takie oczekiwania szczególnie dobrze współpracują z [przekazywaniem zadań asynchronicznie](https://queuety.inline0.dev/pl/docs/workflows/async-handoffs): jeden przepływ pracy uruchamia najpierw niezależne przepływy podrzędne, a później na nie czeka.

Więcej przykładów planisty i wykonawcy znajdziesz w sekcji [Orkiestracja agentów](https://queuety.inline0.dev/pl/docs/workflows/agent-orchestration).

Queuety udostępnia trzy metody konstruktora:

- `wait_for_workflow()` dla jednego przepływu pracy
- `wait_for_workflows()` dla kilku przepływów pracy z semantyką `all`, `any` lub `quorum`
- `wait_for_workflow_group()`, gdy identyfikatory przepływów pochodzą z wcześniej uruchomionej grupy

## Oczekiwanie na jeden przepływ pracy

```php
$research_id = Queuety::workflow( 'research_run' )
    ->then( PlanResearchStep::class )
    ->for_each( 'tasks', ExecuteResearchTask::class, 'results' )
    ->dispatch( [ 'brief_id' => 42 ] );

$editorial_id = Queuety::workflow( 'editorial_run' )
    ->wait_for_workflow( $research_id, 'research' )
    ->then( DraftBriefStep::class )
    ->dispatch();
```

Po zakończeniu `research_run`, `editorial_run` wznawia działanie. Jeśli ustawiono `result_key`, stan zakończonej zależności jest zapisywany pod tym kluczem:

```php
$state['research']; // public state from the completed research workflow
```

Bez `result_key` publiczny stan zależnego przepływu pracy jest scalany z głównym stanem oczekującego przepływu.

## Oczekiwanie na kilka przepływów pracy

```php
use Queuety\Enums\WaitMode;

Queuety::workflow( 'synthesis_run' )
    ->wait_for_workflows(
        [ $research_id, $editorial_id, $legal_id ],
        WaitMode::All,
        'dependencies'
    )
    ->then( PublishPacketStep::class )
    ->dispatch();
```

- `WaitMode::All` wznawia działanie dopiero po zakończeniu wszystkich wymienionych przepływów pracy.
- `WaitMode::Any` wznawia działanie po zakończeniu pierwszego wymienionego przepływu.
- `WaitMode::Quorum` wznawia działanie po pomyślnym zakończeniu wymaganej liczby przepływów pracy.

```php
Queuety::workflow( 'synthesis_run' )
    ->wait_for_workflows(
        [ $research_id, $editorial_id, $legal_id ],
        WaitMode::Quorum,
        'dependencies',
        quorum: 2,
    )
    ->then( PublishPacketStep::class )
    ->dispatch();
```

Przy użyciu `result_key` oczekiwania na wiele przepływów zapisują stan zakończonych zależności pod kluczami będącymi identyfikatorami przepływów pracy:

```php
[
    '42' => [ 'summary' => '...' ],
    '43' => [ 'summary' => '...' ],
]
```

Bez `result_key` stan zakończonych zależności jest scalany z głównym stanem oczekującego przepływu pracy w kolejności zależności.

## Odczytywanie identyfikatorów zależności ze stanu przepływu pracy

Listę zależności możesz ustalić w czasie działania, odczytując identyfikatory przepływów pracy ze stanu publicznego:

```php
Queuety::workflow( 'agent_follow_up' )
    ->wait_for_workflow( 'parent_workflow_id', 'parent' )
    ->then( FinalizeAgentRunStep::class )
    ->dispatch( [ 'parent_workflow_id' => $workflow_id ] );
```

W przypadku kilku zależności:

```php
Queuety::workflow( 'aggregator' )
    ->wait_for_workflows( 'dependency_ids', WaitMode::Any, 'winner' )
    ->dispatch( [ 'dependency_ids' => [ 12, 18, 22 ] ] );
```

## Oczekiwanie na uruchomioną grupę przepływów pracy

Jeśli wcześniejszy krok `start_workflows()` lub `start_agents()` zapisał trwały klucz grupy, możesz bezpośrednio oczekiwać na tę grupę zamiast samodzielnie przekazywać identyfikatory przepływów pracy przez stan publiczny.

```php
Queuety::workflow( 'brief_research' )
    ->then( PlanTopicsStep::class )
    ->start_agents( 'agent_tasks', $agent_run, group_key: 'researchers' )
    ->wait_for_agent_group( 'researchers', WaitMode::Quorum, 2, 'agent_results' )
    ->then( SynthesizeBriefStep::class )
    ->dispatch();
```

## Co dzieje się podczas oczekiwania

Gdy przepływ pracy dociera do jednego z tych kroków, jego status zmienia się na `waiting_for_workflows`. Podczas oczekiwania żaden proces roboczy nie pozostaje z nim powiązany.

```php
$state = Queuety::workflow_status( $workflow_id );
echo $state->status->value; // 'waiting_for_workflows'
echo $state->wait_type;     // 'workflow'
print_r( $state->waiting_for ); // ['42', '43']
```

Jeśli zależny przepływ pracy zakończył się przed osiągnięciem kroku oczekiwania, przepływ jest kontynuowany natychmiast.

## Zasady obsługi niepowodzeń

Oczekiwanie na zależności przepływów pracy opiera się na pomyślnym zakończeniu:

- `wait_for_workflow()` i `WaitMode::All` kończą się niepowodzeniem, jeśli którakolwiek wymagana zależność zakończy się niepowodzeniem lub zostanie anulowana.
- `WaitMode::Any` kończy się niepowodzeniem tylko wtedy, gdy wszystkie zależności osiągną stan końcowy i żadna nie zakończy się pomyślnie.
- `WaitMode::Quorum` kończy się niepowodzeniem, gdy pozostałe aktywne przepływy pracy nie mogą już osiągnąć wymaganej kworum.

Dzięki temu oczekiwanie na przepływy pracy przydaje się w systemach planisty i wykonawcy, w których jeden przepływ może zlecać zadania, a inny czekać na wyniki `all` albo na zakończenie pierwszej pomyślnej gałęzi.
