
# Darbplūsmas signāli

Darbplūsmas var apturēt un gaidīt ārēju ievadi, izmantojot signālus. Veidotāja metodes `wait_for_signal()` un `wait_for_signals()` ievieto darbības, kas aptur darbplūsmu, līdz jūsu lietotne, operators vai cita sistēma nosūta paredzēto signālu, izmantojot `Queuety::signal()`.

Cilvēka iesaistes plūsmām Queuety nodrošina arī:

- `wait_for_approval()` nosaukumvietā ievietotai apstiprinājuma datu paketei
- `wait_for_input()` strukturētai cilvēka ievadei
- `wait_for_decision()` skaidriem apstiprināšanas/noraidīšanas rezultātiem

Plašāku piemēru no sākuma līdz beigām, kur apvienota aģentu palaišana un cilvēku veiktas pārbaudes, skatiet sadaļā [Aģentu orķestrēšana](https://queuety.inline0.dev/lv/docs/workflows/agent-orchestration).

## Metode `->wait_for_signal()`

Pievienojiet darbplūsmai signāla gaidīšanas darbību:

```php
use Queuety\Queuety;

$workflow_id = Queuety::workflow( 'content_approval' )
    ->then( DraftContentHandler::class )
    ->wait_for_signal( 'approved' )
    ->then( PublishContentHandler::class )
    ->dispatch( [ 'post_id' => 99 ] );
```

Kad darbplūsma sasniedz darbību `wait_for_signal`, tās statuss tiek iestatīts uz `waiting_for_signal` un tā tiek apturēta. Gaidīšanas laikā nedarbojas neviens uzdevums un netiek patērēti resursi.

Pēc noklusējuma viens signāla datu kopums tiek apvienots ar darbplūsmas augstākā līmeņa stāvokli. Ja tā vietā vēlaties datu kopumu ievietot nosaukumvietā, norādiet `result_key`:

```php
$workflow_id = Queuety::workflow( 'content_approval' )
    ->then( DraftContentHandler::class )
    ->wait_for_signal( 'approved', 'approval' )
    ->then( PublishContentHandler::class )
    ->dispatch( [ 'post_id' => 99 ] );
```

Pēc signāla saņemšanas `$state['approval']` satur signāla datu masīvu.

## Vairāku signālu gaidīšana

Izmantojiet `wait_for_signals()`, ja darbplūsmai jāturpina izpilde pēc jebkura no vairākiem iespējamiem signāliem vai pirms turpināšanas jāsavāc visi nepieciešamie signāli.

```php
use Queuety\Enums\WaitMode;

$workflow_id = Queuety::workflow( 'moderation_gate' )
    ->then( SubmitForReviewHandler::class )
    ->wait_for_signals(
        [ 'editor_approved', 'legal_approved' ],
        WaitMode::All,
        'approvals'
    )
    ->then( PublishContentHandler::class )
    ->dispatch();
```

- `WaitMode::All` gaida, līdz reģistrēti visi konfigurētie signāli.
- `WaitMode::Any` atsāk izpildi, tiklīdz saņemts pirmais konfigurētais signāls.

Izmantojot `result_key`, vairāku signālu gaidīšanas darbība saglabā asociatīvu masīvu, kura atslēgas ir signālu nosaukumi:

```php
[
    'editor_approved' => [ 'by' => 'editor@example.com' ],
    'legal_approved' => [ 'by' => 'legal@example.com' ],
]
```

Bez `result_key` atbilstošo signālu datu kopumi tiek apvienoti augstākā līmeņa stāvoklī darbības konfigurēšanas secībā.

## Atbilstība un korelācija

Signālu gaidīšanas darbības var ignorēt nesaistītus notikumus, salīdzinot datu saturu vai korelējot pēc kopīgas atslēgas.

```php
$workflow_id = Queuety::workflow( 'review_gate' )
    ->wait_for_signal(
        name: 'review_ready',
        result_key: 'review',
        match_payload: [ 'source' => 'editorial' ],
        correlation_key: 'task_id',
    )
    ->dispatch( [ 'task_id' => 'task-42' ] );
```

Šajā piemērā gaidīšana tiek pārtraukta tikai tad, ja:

- signāla nosaukums ir `review_ready`
- datu kopumā ir ietverts `source: editorial`
- datu kopuma vērtība `task_id` atbilst `$state['task_id']`

Tas noder, ja vairākas ārējās sistēmas vai aģenti publicē notikumus ar vienādiem nosaukumiem, bet tikai viena datu kopa pieder pašreizējai darbplūsmas izpildei.

## Cilvēka apstiprināšanas un ievades palīgmetodes

`wait_for_approval()` un `wait_for_input()` ir signālu gaidīšanas ērtākas versijas. Tās darbojas tāpat kā `wait_for_signal()`, taču pēc noklusējuma rezultāta atslēgu ievieto nosaukumvietā.

```php
$workflow_id = Queuety::workflow( 'blog_review' )
    ->then( GenerateDraftHandler::class )
    ->wait_for_approval()
    ->wait_for_input()
    ->then( HandleDecisionHandler::class )
    ->dispatch();
```

Pēc signāla `approval` saņemšanas `$state['approval']` satur apstiprinājuma datu kopu. Pēc signāla `input` saņemšanas `$state['input']` satur ievades datu kopu.

Izmantojiet `wait_for_decision()`, ja vēlaties, lai viena darbība atsāktu izpildi gan pēc apstiprinājuma, gan noraidījuma:

```php
$workflow_id = Queuety::workflow( 'legal_review' )
    ->then( DraftContractHandler::class )
    ->wait_for_decision( result_key: 'review' )
    ->then( HandleReviewDecisionHandler::class )
    ->dispatch();
```

Pēc signāla saņemšanas `$state['review']` satur:

```php
[
    'outcome' => 'approved', // or 'rejected'
    'signal'  => 'approved', // or 'rejected'
    'data'    => [ 'reviewer' => 'ops@example.com' ],
]
```

## Signāla nosūtīšana

Nosūtiet darbplūsmai signālu, izmantojot `Queuety::signal()`:

```php
Queuety::signal( $workflow_id, 'approved' );
```

Ja signāls atbilst tam, ko darbplūsma gaida, darbplūsma atsāk izpildi un pāriet uz nākamo darbību.

Cilvēka iesaistes plūsmām fasāde piedāvā arī semantiskas palīgmetodes:

```php
Queuety::approve_workflow( $workflow_id, [ 'reviewer' => 'editor@example.com' ] );
Queuety::reject_workflow( $workflow_id, [ 'reason' => 'needs citations' ] );
Queuety::submit_workflow_input( $workflow_id, [ 'notes' => 'Ship after copy edit' ] );
```

### Signāla dati

Kopā ar signālu varat nodot datu masīvu. Dati tiek apvienoti darbplūsmas stāvoklī un kļūst pieejami turpmākajām darbībām:

```php
Queuety::signal( $workflow_id, 'approved', [
    'approved_by' => 'admin@example.com',
    'approved_at' => time(),
] );
```

Nākamajā darbībā:

```php
class PublishContentHandler implements Step {
    public function handle( array $state ): array {
        // $state['approved_by'] is 'admin@example.com'
        // $state['approved_at'] is the timestamp
        // $state['post_id'] is 99
        wp_update_post( [
            'ID'          => $state['post_id'],
            'post_status' => 'publish',
        ] );
        return [ 'published' => true ];
    }

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

Atslēgas, kas sākas ar `_` (pasvītrojuma zīmi), ir rezervētas iekšējai lietošanai un netiek apvienotas ar stāvokli.

## Jau iepriekš saņemti signāli

Signālus var nosūtīt, pirms darbplūsma sasniedz gaidīšanas darbību. Saņemot signālu, tas tiek ierakstīts tabulā `queuety_signals` neatkarīgi no darbplūsmas pašreizējā statusa. Kad darbplūsma vēlāk sasniedz darbību `wait_for_signal`, tā pārbauda, vai nav iepriekš saņemtu signālu, un, ja tādu atrod, nekavējoties turpina izpildi.

Tas nozīmē, ka secībai nav nozīmes:

```php
// Dispatch workflow
$workflow_id = Queuety::workflow( 'order_fulfillment' )
    ->then( PrepareOrderHandler::class )
    ->wait_for_signal( 'payment_confirmed' )
    ->then( ShipOrderHandler::class )
    ->dispatch( [ 'order_id' => 123 ] );

// Signal arrives before the workflow reaches the wait step
Queuety::signal( $workflow_id, 'payment_confirmed', [ 'transaction_id' => 'txn_abc' ] );

// When the workflow finishes PrepareOrderHandler and reaches the wait step,
// it sees the pre-existing signal and continues immediately.
```

## Darbplūsmas statuss, gaidot signālu

Gaidot signālu, darbplūsmas statuss ir `WorkflowStatus::WaitingForSignal` (`waiting_for_signal`):

```php
$state = Queuety::workflow_status( $workflow_id );
echo $state->status->value; // 'waiting_for_signal'
echo $state->wait_type;     // 'signal'
echo $state->wait_mode;     // 'all' or 'any'
print_r( $state->waiting_for ); // ['approved']
print_r( $state->wait_details ); // matched/remaining, correlation info, result key, ...
```

## Lietojuma gadījums: cilvēka apstiprinājums

Izveidojiet apstiprināšanas darbplūsmu, kurā cilvēkam pirms publicēšanas jāapstiprina saturs:

```php
$workflow_id = Queuety::workflow( 'blog_review' )
    ->then( GenerateDraftHandler::class )
    ->then( NotifyReviewerHandler::class )
    ->wait_for_decision( result_key: 'review' )
    ->then( HandleDecisionHandler::class )
    ->dispatch( [ 'topic' => 'PHP middleware patterns' ] );
```

`NotifyReviewerHandler` nosūta e-pastu vai Slack ziņojumu ar apstiprināšanas/noraidīšanas saitēm. Šīs saites izsauc jūsu kontrolieri, kas nosūta signālu:

```php
// In your approval controller
Queuety::approve_workflow(
    $workflow_id,
    [
        'reviewer'    => $current_user->user_email,
        'reviewed_at' => time(),
    ],
    'approved'
);
```

Darbība `HandleDecisionHandler` nolasa `$state['review']['outcome']` un publicē vai arhivē melnrakstu.

## Lietojuma gadījums: ārēja API atzvans

Gaidiet ārēja pakalpojuma webhook:

```php
$workflow_id = Queuety::workflow( 'generate_video' )
    ->then( SubmitToRenderServiceHandler::class )
    ->wait_for_signal( 'render_complete' )
    ->then( DownloadVideoHandler::class )
    ->then( NotifyUserHandler::class )
    ->dispatch( [ 'template_id' => 'promo_v2', 'user_id' => 42 ] );
```

Kad ārējais pakalpojums nosūta pieprasījumu jūsu webhook galapunktam:

```php
// In your webhook handler
$payload = json_decode( file_get_contents( 'php://input' ), true );
$workflow_id = (int) $payload['metadata']['workflow_id'];

Queuety::signal( $workflow_id, 'render_complete', [
    'video_url'  => $payload['output_url'],
    'duration'   => $payload['duration_seconds'],
] );
```

## Vairāki signālu vārti vienā darbplūsmā

Darbplūsma var gaidīt signālus vairākos punktos:

```php
Queuety::workflow( 'multi_approval' )
    ->then( CreateProposalHandler::class )
    ->wait_for_signal( 'manager_approval' )
    ->then( EscalateToDirectorHandler::class )
    ->wait_for_signal( 'director_approval' )
    ->then( ExecuteProposalHandler::class )
    ->dispatch( [ 'proposal_id' => 7 ] );
```

Katra signāla gaidīšanas darbība ir neatkarīga. Vienā darbplūsmā varat apvienot `wait_for_signal()`, `wait_for_signals()`, `wait_for_approval()`, `wait_for_input()` un `wait_for_decision()`.
