Workflowsignaler
Workflows kan sættes på pause og vente på eksternt input via signaler. Buildermetoderne wait_for_signal() og wait_for_signals() indsætter trin, der blokerer workflowet, indtil din applikation, en operatør eller et andet system sender det forventede signal via Queuety::signal().
Til forløb med mennesker i løkken indeholder Queuety også:
wait_for_approval()til en navneområdeforankret godkendelsesnyttelastwait_for_input()til struktureret menneskeligt inputwait_for_decision()til eksplicitte godkendelses-/afvisningsresultater
Se Agentorkestrering for et større eksempel fra start til slut, der kombinerer agentkørsler med menneskelige kontrolpunkter.
Metoden ->wait_for_signal()
Føj et signalventetrin til et workflow:
use Queuety\Queuety;
$workflow_id = Queuety::workflow( 'content_approval' )
->then( DraftContentHandler::class )
->wait_for_signal( 'approved' )
->then( PublishContentHandler::class )
->dispatch( [ 'post_id' => 99 ] );
Når workflowet når trinnet wait_for_signal, ændres dets status til waiting_for_signal, og det sættes på pause. Der kører ingen jobs, og der forbruges ingen ressourcer, mens det venter.
Som standard flettes én signalnyttelast ind i workflowtilstanden på øverste niveau. Hvis nyttelasten i stedet skal placeres i et navneområde, skal du angive en result_key:
$workflow_id = Queuety::workflow( 'content_approval' )
->then( DraftContentHandler::class )
->wait_for_signal( 'approved', 'approval' )
->then( PublishContentHandler::class )
->dispatch( [ 'post_id' => 99 ] );
Når signalet ankommer, indeholder $state['approval'] arrayet med signalnyttelaster.
Vent på flere signaler
Brug wait_for_signals(), når workflowet skal genoptages ved et af flere mulige signaler, eller når det skal indsamle alle påkrævede signaler, før det fortsætter.
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::Allventer, indtil alle konfigurerede signaler er registreret.WaitMode::Anygenoptages, så snart det første konfigurerede signal ankommer.
Med en result_key gemmer en ventetid på flere signaler et associativt array, hvor nøglerne er signalnavne:
[
'editor_approved' => [ 'by' => 'editor@example.com' ],
'legal_approved' => [ 'by' => 'legal@example.com' ],
]
Uden en result_key flettes de matchende signalnyttelaster ind i tilstanden på øverste niveau i den rækkefølge, trinnet blev konfigureret.
Matchning og korrelation
Signalventetider kan ignorere uvedkommende hændelser ved at matche indholdet af nyttelasten eller korrelere efter en delt nøgle.
$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' ] );
I dette eksempel genoptages ventetiden kun, når:
- signalnavnet er
review_ready - nyttelasten indeholder
source: editorial - nyttelastens
task_idmatcher$state['task_id']
Dette er nyttigt, når flere eksterne systemer eller agenter udsender de samme hændelsesnavne, men kun én nyttelast hører til den aktuelle workflowkørsel.
Hjælpere til menneskelig godkendelse og input
wait_for_approval() og wait_for_input() er praktiske omslag om signalventepunkter. De fungerer som wait_for_signal(), men bruger som standard en navnerumsopdelt resultatnøgle.
$workflow_id = Queuety::workflow( 'blog_review' )
->then( GenerateDraftHandler::class )
->wait_for_approval()
->wait_for_input()
->then( HandleDecisionHandler::class )
->dispatch();
Efter signalet approval indeholder $state['approval'] godkendelsesnyttelasten. Efter signalet input indeholder $state['input'] inputnyttelasten.
Brug wait_for_decision(), når du vil have et enkelt trin til at fortsætte ved enten godkendelse eller afvisning:
$workflow_id = Queuety::workflow( 'legal_review' )
->then( DraftContractHandler::class )
->wait_for_decision( result_key: 'review' )
->then( HandleReviewDecisionHandler::class )
->dispatch();
Når signalet er modtaget, indeholder $state['review']:
[
'outcome' => 'approved', // or 'rejected'
'signal' => 'approved', // or 'rejected'
'data' => [ 'reviewer' => 'ops@example.com' ],
]
Afsendelse af et signal
Send et signal til et workflow med Queuety::signal():
Queuety::signal( $workflow_id, 'approved' );
Når signalet matcher det, workflowet venter på, fortsætter workflowet til næste trin.
Til human-in-the-loop-forløb stiller facaden også semantiske hjælpere til rådighed:
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' ] );
Signalinformation
Du kan sende et dataarray med signalet. Dataene flettes ind i workflowtilstanden, så de er tilgængelige for de efterfølgende trin:
Queuety::signal( $workflow_id, 'approved', [
'approved_by' => 'admin@example.com',
'approved_at' => time(),
] );
I næste trin:
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 [];
}
}
Nøgler, der begynder med _ (understreg), er reserveret til intern brug og flettes ikke ind i tilstanden.
Forudgående signaler
Signaler kan sendes, før workflowet når ventetrinnet. Når et signal modtages, registreres det i tabellen queuety_signals uanset workflowets aktuelle status. Når workflowet senere når trinnet wait_for_signal, søger det efter forudgående signaler og fortsætter straks, hvis et findes.
Det betyder, at rækkefølgen er ligegyldig:
// 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.
Workflowstatus under signalventning
Mens workflowet venter på et signal, er status WorkflowStatus::WaitingForSignal (waiting_for_signal):
$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, ...
Anvendelse: menneskelig godkendelse
Byg et godkendelsesworkflow, hvor en menneskelig kontrollant skal godkende indhold, før det offentliggøres:
$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 sender en e-mail eller en Slack-meddelelse med links til godkendelse/afvisning. Linkene kalder din controller, som sender signalet:
// In your approval controller
Queuety::approve_workflow(
$workflow_id,
[
'reviewer' => $current_user->user_email,
'reviewed_at' => time(),
],
'approved'
);
Trinnet HandleDecisionHandler læser $state['review']['outcome'] og enten offentliggør eller arkiverer kladden.
Anvendelse: eksternt API-callback
Vent på et webhook fra en ekstern tjeneste:
$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 ] );
Når den eksterne tjeneste sender en anmodning til dit webhook-endpoint:
// 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'],
] );
Flere signalporte i ét workflow
Et workflow kan vente på signaler flere steder:
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 ] );
Hvert signalventetrin er uafhængigt. Du kan kombinere wait_for_signal(), wait_for_signals(), wait_for_approval(), wait_for_input() og wait_for_decision() i samme workflow.