Signal Handling Example
This example demonstrates how to use signals to interact with running flows in ZoopFlow. Signals provide a way to communicate with long-running flows, allowing for modifications, cancellations, and updates during execution.
What You'll Learn
- How to define signals with type safety
- How to register signals with a flow registry and signal manager
- How to send signals to running workflows
- How to handle signals within a workflow context
- How to update flow state and execution based on signals
- Common signal handling patterns with middleware support
Files in this Example
signal-definitions.ts- Demonstrates how to define signals with proper typingorder-processing-flow.ts- A sample flow that handles cancellation and update signalsflow-registration.ts- Shows how to register flows and signals with the Temporal integrationclient.ts- Example of sending signals to a running workflowrun-example.ts- Entry point to run the example
Signal Handling Concepts
In ZoopFlow, signals:
- Can be registered globally or with specific flow registries
- Allow external systems to communicate with running workflows
- Have defined schemas with JSON Schema validation for type-safe payloads
- Can be processed through middleware for cross-cutting concerns
- Can be used to update workflow state through the SignalContext
- Enable workflows to respond to external events
- Include standard handlers for common operations (pause, resume, cancel, update)
- Provide history tracking and checkpoint creation
- Are crucial for long-running business processes
Flow-Specific Signal Registration
ZoopFlow uses a flow-specific approach to signal registration, where each signal handler is associated with a specific flow. This design provides several benefits:
- Isolation: Signals for one flow don't affect others
- Context Relevance: Handlers receive context specific to their flow
- Clearer Boundaries: Explicit association between flows and signals
- Reduced Naming Conflicts: Same signal name can be used in different flows
How to Run
# From the project root
npm install
npm run build
node dist/examples/signal-handling/run-example.jsExpected Output
The example will:
- Start an order processing workflow
- Send a signal to update the shipping address
- Optionally send a signal to cancel the order
- Show how the workflow responds to these signals
- Demonstrate state changes based on signals
Output will show signal delivery and how the flow execution changes in response.
Code Example: Signal Registration
// flow-registration.ts
import { registerTemporalFlowControlSignals } from '@zoop/flow/core/signals/temporal';
import { SignalRegistryImpl } from '@zoop/flow/core/signals/core';
import { SignalManager, createLoggingMiddleware } from '@zoop/flow/core/signals/manager';
import { orderProcessingFlow } from './order-processing-flow';
import {
cancelOrderSignal,
updateAddressSignal,
paymentReceivedSignal
} from './signal-definitions';
// Create a registry specific to this flow
const orderFlowRegistry = new SignalRegistryImpl();
// Register signals with the registry
orderFlowRegistry.registerSignal(cancelOrderSignal);
orderFlowRegistry.registerSignal(updateAddressSignal);
orderFlowRegistry.registerSignal(paymentReceivedSignal);
// Create a signal manager with middleware
const signalManager = new SignalManager(orderFlowRegistry, {
queueSignalsUntilInitialized: true,
middleware: [
createLoggingMiddleware(),
// Add more middleware as needed
]
});
// When setting up the Temporal workflow
function setupOrderWorkflow(workflowId: string, executionId: string, temporalContext: any) {
// Register standard flow control signals (pause, resume, cancel, update)
registerTemporalFlowControlSignals(
orderProcessingFlow.id,
executionId,
temporalContext
);
// Initialize the signal manager
signalManager.markInitialized();
}Sending Signals to a Flow
// client.ts
import { Connection, WorkflowClient } from '@temporalio/client';
async function sendSignalToWorkflow() {
// Connect to Temporal server
const connection = await Connection.connect();
const client = new WorkflowClient({ connection });
// Get a handle to the running workflow
const workflowId = 'order-123456';
const handle = client.getHandle(workflowId);
// Send a signal to update the shipping address
// The signal ID format is namespace.name
await handle.signal('order.updateAddress', {
orderId: workflowId,
address: {
street: '123 Main St',
city: 'Anytown',
state: 'CA',
zip: '12345'
}
});
console.log('Address update signal sent successfully');
}Next Steps
- Create your own custom signals for specific flow scenarios
- Implement middleware for custom validation, logging, or transformation
- Use the history tracking and checkpoint features for auditability
- Learn about integration with Temporal in the Temporal Integration Example
- Implement a real-world use case with flow-specific signals
- Try the built-in flow control signals (pause, resume, cancel, update)
- Explore signal state management for complex workflow control