
# Parallella steg

Ibland kan flera steg köras samtidigt. Metoden `->parallel()` skickar en grupp hanterare för samtidig körning. Arbetsflödet går vidare först när alla parallella hanterare har slutförts.

## Metoden `->parallel()`

```php
use Queuety\Queuety;

Queuety::workflow( 'enrich_profile' )
    ->then( FetchUserHandler::class )
    ->parallel( [
        FetchSocialProfileHandler::class,
        FetchPaymentHistoryHandler::class,
        FetchActivityLogHandler::class,
    ] )
    ->then( MergeAndSaveHandler::class )
    ->dispatch( [ 'user_id' => 42 ] );
```

I det här exemplet:
1. Körs `FetchUserHandler` först (sekventiellt)
2. Körs tre hanterare samtidigt (parallellt)
3. Körs `MergeAndSaveHandler` när alla tre har slutförts (sekventiellt)

## Så fungerar det

När ett parallellt steg nås skickar Queuety ett jobb per hanterare i gruppen. Varje jobb får arbetsflödets aktuella tillstånd och körs oberoende av de andra. Arbetsflödet håller reda på hur många parallella jobb som återstår och går vidare till nästa steg först när alla har slutförts.

Returvärdet från varje parallell hanterare sammanfogas med arbetsflödets tillstånd. Om flera hanterare returnerar samma nyckel vinner den som slutförs sist.

## Sammanfogning av tillstånd

Varje parallell hanterare returnerar data som sammanfogas med det delade arbetsflödestillståndet:

```php
class FetchSocialProfileHandler implements Step {
    public function handle( array $state ): array {
        $profile = fetch_social_api( $state['user_id'] );
        return [ 'social_profile' => $profile ];
    }

    public function config(): array {
        return [];
    }
}

class FetchPaymentHistoryHandler implements Step {
    public function handle( array $state ): array {
        $payments = fetch_payment_api( $state['user_id'] );
        return [ 'payment_history' => $payments ];
    }

    public function config(): array {
        return [];
    }
}
```

När det parallella steget har slutförts innehåller tillståndet både `social_profile` och `payment_history`, och nästa sekventiella steg kan komma åt allt.

## Blanda sekventiella och parallella steg

Du kan fritt blanda anrop till `->then()` och `->parallel()`:

```php
Queuety::workflow( 'complex_pipeline' )
    ->then( SetupHandler::class )               // sequential
    ->parallel( [ TaskA::class, TaskB::class ] ) // parallel
    ->then( IntermediateHandler::class )         // sequential
    ->parallel( [ TaskC::class, TaskD::class ] ) // parallel
    ->then( FinalizeHandler::class )             // sequential
    ->dispatch( $payload );
```

## Felhantering

Om någon hanterare i en parallell grupp misslyckas följer arbetsflödet den vanliga omförsökslogiken för den hanteraren. Andra parallella hanterare som redan har slutförts körs inte igen. När den misslyckade hanteraren lyckas fortsätter arbetsflödet. Om den förbrukar alla sina omförsök och begravs markeras arbetsflödet som misslyckat och de återstående grenjobben begravs. Använd `retry_workflow()` för att köra det misslyckade steget igen.
