@@ -415,61 +415,127 @@ export const exampleWorkflow = workflow.define({
415415});
416416```
417417
418- ### Awaiting events with ` ctx.awaitEvent `
418+ ### Waiting for external events
419419
420420Use ` ctx.awaitEvent ` inside a workflow handler to pause until an external event
421- is delivered. This is useful for human-in-the-loop flows or coordinating with
422- other systems.
421+ is triggered. This is useful for human-in-the-loop flows or coordinating with
422+ other asynchronous flows. Wait for an indefinite amount of time and continue
423+ when the event is triggered.
423424
424425At its simplest, you can wait for an event ** by name** :
425426
426427``` ts
427- await ctx .awaitEvent ({ name: " approval " });
428+ await ctx .awaitEvent ({ name: " eventName " });
428429```
429430
430- or for a ** specific event by ID** :
431+ This will wait for the first un-consumed event with the name "eventName", and
432+ will continue immediately if one was already sent. Events are sent by calling
433+ ` workflow.sendEvent ` from a mutation or action:
431434
432435``` ts
433- await ctx .awaitEvent ({ id: signalId });
436+ await workflow .sendEvent (ctx , {
437+ name: " eventName" ,
438+ workflowId ,
439+ });
434440```
435441
436- To unblock a waiting workflow, call ` workflow.sendEvent ` from a mutation or
437- action. You can send a value with the event, or send an error that will cause
438- ` ctx.awaitEvent ` to throw. See
439- [ ` example/convex/passingSignals.ts ` ] ( ./example/convex/passingSignals.ts ) for a
440- complete example of creating events, passing their IDs around, and sending
441- signals.
442+ Note: You must send the event on the same workflow component that is waiting for
443+ it, and the workflowId must match the ID of the workflow that is waiting for it.
444+
445+ #### Sending values or errors with the event
442446
443- #### Sharing event definitions with ` defineEvent `
447+ You can send a value with the event using the ` value ` property. For type safety
448+ and runtime validation, provide a validator on the sending and receiving sides.
449+
450+ ``` ts
451+ const sharedValidator = v .number ();
452+
453+ // In the workflow:
454+ const event = await ctx .awaitEvent ({ name , validator: sharedValidator });
455+
456+ // From elsewhere:
457+ await workflow .sendEvent (ctx , { name , workflowId , value: 42 });
458+ ```
459+
460+ To send an error, use the ` error ` property. This will cause ` ctx.awaitEvent ` to
461+ throw an error.
462+
463+ ``` ts
464+ await workflow .sendEvent (ctx , { name , workflowId , error: " An error occurred" });
465+ ```
466+
467+ #### Sharing event definitions
444468
445469Use ` defineEvent ` to define an event's name and validator in one place, then
446470share it between the workflow and the sender:
447471
448472``` ts
449473const approvalEvent = defineEvent ({
450- name: " approval" as const ,
474+ name: " approval" ,
451475 validator: v .object ({ approved: v .boolean () }),
452476});
453477
454478// In the workflow:
455479const approval = await ctx .awaitEvent (approvalEvent );
456480
457481// From a mutation:
458- await workflow .sendEvent (ctx , { ... approvalEvent , workflowId , value: { approved: true } });
482+ const value = { approved: true };
483+ await workflow .sendEvent (ctx , { ... approvalEvent , workflowId , value });
459484```
460485
461486See [ ` example/convex/userConfirmation.ts ` ] ( ./example/convex/userConfirmation.ts )
462487for a full approval flow built this way.
463488
489+ Note: this is just a convenience to create a typed { event, validator } pair.
490+
491+ #### Waiting for dynamically created events by ID
492+
493+ You can also dynamically create an event with ` createEvent ` :
494+
495+ ``` ts
496+ const eventId = await workflow .createEvent (ctx , {
497+ name: " userResponse" ,
498+ workflowId ,
499+ });
500+ ```
501+
502+ Then wait for it by ID in the workflow:
503+
504+ ``` ts
505+ await ctx .awaitEvent ({ id: eventId });
506+ ```
507+
508+ This works well when there are dynamically defined events, for instance a tool
509+ that is waiting for a response from a user. You would save the eventId somewhere
510+ to be able to send the event later with ` workflow.sendEvent ` :
511+
512+ ``` ts
513+ await workflow .sendEvent (ctx , { id: eventId });
514+ ```
515+
516+ Similar to named events, you can also send a value or error with the event.
517+
518+ See [ ` example/convex/passingSignals.ts ` ] ( ./example/convex/passingSignals.ts ) for
519+ a complete example of creating events, passing their IDs around, and sending
520+ signals.
521+
464522### Running nested workflows with ` ctx.runWorkflow `
465523
466524Use ` ctx.runWorkflow ` to run another workflow as a single step in the current
467525one. The parent workflow waits for the nested workflow to finish and receives
468- its return value: ` const result = await ctx.runWorkflow(internal.example.childWorkflow, { args }); `
526+ its return value:
527+ ` const result = await ctx.runWorkflow(internal.example.childWorkflow, { args }); `
469528
470529You can also specify scheduling options like ` { runAfter: 5000 } ` to delay the
471- nested workflow. See [ ` example/convex/nestedWorkflow.ts ` ] ( ./example/convex/nestedWorkflow.ts )
472- for a complete parent/child workflow example.
530+ nested workflow. See
531+ [ ` example/convex/nestedWorkflow.ts ` ] ( ./example/convex/nestedWorkflow.ts ) for a
532+ complete parent/child workflow example.
533+
534+ To associate the child workflow with the parent in your own tables, you can pass
535+ the ` ctx.workflowId ` to the child workflow as an argument, and/or return the
536+ child's workflowId to the parent.
537+
538+ The status of the parent workflow will include any active child workflowIds.
473539
474540## Tips and troubleshooting
475541
0 commit comments