Arbetsflödessignaler
Arbetsflöden kan pausas och vänta på extern indata med hjälp av signaler. Byggmetoderna wait_for_signal() och wait_for_signals() lägger in steg som blockerar arbetsflödet tills din applikation, en operatör eller ett annat system skickar den förväntade signalen via Queuety::signal().
För flöden med mänsklig medverkan innehåller Queuety även:
wait_for_approval()för en namnområdesindelad godkännandenyttolastwait_for_input()för strukturerad mänsklig indatawait_for_decision()för uttryckliga resultat för godkännande/avslag
För ett större exempel från början till slut som kombinerar agentkörningar med mänskliga kontrollpunkter, se Agentorkestrering.
Metoden ->wait_for_signal()
Lägg till ett steg som väntar på en signal i ett arbetsflöde:
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 arbetsflödet når steget wait_for_signal ändras dess status till waiting_for_signal och det pausas. Inga jobb körs och inga resurser förbrukas medan det väntar.
Som standard slås en enda signalnyttolast samman med arbetsflödets tillstånd på toppnivå. Om du i stället vill att nyttolasten ska ligga i ett namnområde skickar du med 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 signalen kommer innehåller $state['approval'] signalnyttolastens array.
Vänta på flera signaler
Använd wait_for_signals() när arbetsflödet ska låsas upp av någon av flera möjliga signaler, eller när det måste samla in alla obligatoriska signaler innan 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::Allväntar tills varje konfigurerad signal har registrerats.WaitMode::Anyfortsätter så snart den första konfigurerade signalen kommer.
Med en result_key lagrar en väntan på flera signaler en associativ array vars nycklar är signalnamnen:
[
'editor_approved' => [ 'by' => 'editor@example.com' ],
'legal_approved' => [ 'by' => 'legal@example.com' ],
]
Utan en result_key slås nyttolasterna från matchade signaler samman med tillståndet på toppnivå i den ordning steget konfigurerades.
Matchning och korrelation
Väntesteg för signaler kan ignorera orelaterade händelser genom att matcha nyttolastens innehåll eller korrelera med en delad nyckel.
$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 det exemplet återupptas väntan bara när:
- signalnamnet är
review_ready - nyttolasten innehåller
source: editorial - nyttolasten
task_idmatchar$state['task_id']
Detta är användbart när flera externa system eller agenter publicerar samma händelsenamn, men bara en nyttolast hör till den aktuella arbetsflödeskörningen.
Hjälpfunktioner för mänskligt godkännande och indata
wait_for_approval() och wait_for_input() är förenklade omslag runt signalväntan. De fungerar som wait_for_signal() men använder som standard en resultatnyckel i ett namnområde.
$workflow_id = Queuety::workflow( 'blog_review' )
->then( GenerateDraftHandler::class )
->wait_for_approval()
->wait_for_input()
->then( HandleDecisionHandler::class )
->dispatch();
Efter signalen approval innehåller $state['approval'] godkännandenyttolasten. Efter signalen input innehåller $state['input'] indatan nyttolast.
Använd wait_for_decision() när du vill att ett enda steg ska fortsätta vid antingen godkännande eller avslag:
$workflow_id = Queuety::workflow( 'legal_review' )
->then( DraftContractHandler::class )
->wait_for_decision( result_key: 'review' )
->then( HandleReviewDecisionHandler::class )
->dispatch();
När signalen kommer innehåller $state['review']:
[
'outcome' => 'approved', // or 'rejected'
'signal' => 'approved', // or 'rejected'
'data' => [ 'reviewer' => 'ops@example.com' ],
]
Skicka en signal
Skicka en signal till ett arbetsflöde med Queuety::signal():
Queuety::signal( $workflow_id, 'approved' );
När signalen matchar den som arbetsflödet väntar på fortsätter arbetsflödet och går vidare till nästa steg.
För flöden med mänsklig medverkan har fasaden även semantiska hjälpfunktioner:
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' ] );
Signaldata
Du kan skicka med en dataarray med signalen. Data slås samman med arbetsflödestillståndet och blir tillgängliga för efterföljande steg:
Queuety::signal( $workflow_id, 'approved', [
'approved_by' => 'admin@example.com',
'approved_at' => time(),
] );
I nästa steg:
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 [];
}
}
Nycklar som börjar med _ (understreck) är reserverade för intern användning och slås inte samman med tillståndet.
Befintliga signaler
Signaler kan skickas innan arbetsflödet når väntesteget. När en signal kommer registreras den i tabellen queuety_signals oavsett arbetsflödets aktuella status. När arbetsflödet senare når steget wait_for_signal söker det efter befintliga signaler och fortsätter omedelbart om en hittas.
Det innebär att ordningen inte spelar någon roll:
// 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.
Arbetsflödets status medan det väntar på signal
Medan arbetsflödet väntar på en signal är statusen 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, ...
Användningsfall: mänskligt godkännande
Bygg ett godkännandearbetsflöde där en mänsklig granskare måste godkänna innehållet innan det publiceras:
$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 skickar ett e-postmeddelande eller ett Slack-meddelande med länkar för att godkänna eller avslå. Länkarna anropar din styrenhet, som skickar signalen:
// In your approval controller
Queuety::approve_workflow(
$workflow_id,
[
'reviewer' => $current_user->user_email,
'reviewed_at' => time(),
],
'approved'
);
Steget HandleDecisionHandler läser $state['review']['outcome'] och publicerar eller arkiverar sedan utkastet.
Användningsfall: extern API-återkoppling
Vänta på en webhook från en extern tjänst:
$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 externa tjänsten skickar ett anrop till din webhook-slutpunkt:
// 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'],
] );
Flera signalkontroller i ett arbetsflöde
Ett arbetsflöde kan vänta på signaler vid flera tillfällen:
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 ] );
Varje signalväntesteg är oberoende. Du kan blanda wait_for_signal(), wait_for_signals(), wait_for_approval(), wait_for_input() och wait_for_decision() i samma arbetsflöde.