Events
The events service in Flows provides a powerful way for blocks to communicate with each other through asynchronous event-based messaging. This allows for building complex workflows where different blocks can react to events emitted by other blocks.
Events in Flows are messages that can be emitted by one block and received by others. The events system is built around the block component model, where:
- Blocks can define inputs (to receive events)
- Blocks can define outputs (to emit events)
- Events flow through a socket, from the output of one block to the connected inputs of another block
This creates a flexible system for building event-driven workflows.
Emitting eventsยป
Events are emitted using the events.emit function, through outputs defined in a block's component. This section covers how to define such outputs and how to use the emission function.
Defining outputsยป
Before you emit an event, you need to define the output in your block's schema. The output definition specifies the name, description, and type of events that will be emitted. Types can be simple (like "string", "number", "boolean") or complex, typed using JSON Schema.
1 2 3 4 5 6 7 8 9 10 11 12 | |
The events.emit functionยป
The only way to emit events is through the emit function:
1 2 3 | |
Arguments:
event: The event payload (can be any serializable object)options: Optional configuration for the event
Options object:
1 2 3 4 5 6 7 | |
Most blocks will react to events by emitting one or more events on one or more outputs. However, some blocks will emit events from different triggers - such as incoming HTTP requests, schedules, internal timers, internal messages or user actions from the GUI such as re-emitting a previous event.
Basic usageยป
To emit a simple event:
1 | |
To emit on a specific output:
1 2 3 4 | |
Mind the key
When using outputKey, the key must match one of the outputs defined in your block's component. If an invalid outputKey is provided, an error will be thrown. You don't need to specify outputKey if your block has only one output.
Event parentageยป
Automatic parent assignmentยป
When emitting an event directly from within an onEvent handler, the current event being handled is automatically assigned as the parent:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Manual parent assignmentยป
However, in cases where you need to emit an event outside the direct flow of an event handler (such as in a timer handler or HTTP callback), you must explicitly specify the parent event ID. Otherwise, the emitted event will not have any parentage information, meaning downstream blocks will not have access to data carried by upstream events.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |
Receiving eventsยป
To receive events, blocks must define at least one input in their component and implement an onEvent handler for it.
Configuring block inputsยป
In this example, we define a block with an input that listens for events. The input has a configuration parameter someValue. It is required, meaning that it has to be filled out - either statically by the user, or dynamically referring to data from one of the upstream blocks.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |
Advanced topicsยป
Event Echoยป
When an event is processed by a block that already processed one of its ancestors, we call the past event an echo. The echo feature provides a powerful way to automatically access previous events in a workflow that were emitted by the same block.
How Echo Worksยป
The echo system automatically identifies the most recent event in an event's ancestry that was emitted by the current block. It makes this previous event available as part of the input, eliminating the need to manually track relationships between events.
For example, with an HTTP Endpoint block:
- When a request comes in, the block emits an event (the outgoing event)
- Later, when a response event comes back to the block (the incoming event)
- The echo system automatically includes the original request event in the incoming event's data
This solves a common challenge in request-response patterns: matching responses to their original requests without requiring manual tracking.
Using Echoยป
To enable echo for an emitted event:
1 2 3 4 | |
When a block later receives an event that has one of its own events in its ancestry, the original event will be available in the input:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |
The echo contains additional metadata:
- The original event body (
body) - The key of the output on which the event was emitted (
outputKey) - The ID of the original event (
id)
Benefits and Use Casesยป
Echo is particularly valuable for:
- HTTP request/response patterns
- Multi-step workflows where a block needs to match responses with original requests
- Any scenario where maintaining context across multiple events is important
By automatically tracking event relationships, echo eliminates the need for developers to implement manual tracking systems and simplifies the user experience when building workflows. An excellent example of echo is the Subroutine Definition block from the core Utilities app.
echo is not automatic!
Blocks need to explicitly request echo capability to receive echo data in the events.emit options, as it requires additional processing.
Secondary Parentsยป
Events can have multiple parent relationships through secondary parents:
1 2 3 4 5 6 7 8 | |
Purpose of secondary parentsยป
Secondary parents serve a specialized purpose in the Flows event system. They are:
-
Visual lineage tracking: Secondary parents are primarily used for visualizing event relationships in the Event History view, showing which other events influenced or contributed to the current event.
-
Documentation of relationships: They help document complex event flows where multiple upstream events contribute to a single downstream event.
-
No data availability to downstream blocks: Unlike primary parents, secondary parent event data is NOT made available to downstream blocks that receive the event.
When to use secondary parentsยป
Secondary parents are most useful in scenarios such as:
- Merge operations: When a block combines data from multiple sources or events
- Aggregation patterns: When collecting multiple events before producing a summary event
- Multi-input transformations: When an operation depends on multiple input events
Pending Eventsยป
Pending events represent future events that are expected to occur, providing visibility into asynchronous processing. They transform events from point-in-time occurrences into observable processes with duration, showing users what's happening during long-running operations.
Purposeยป
Pending events address the observability gap that occurs when a block processes an event asynchronously. They show:
- What's happening with the event
- When a response might be expected
- Which output will emit the response
- Preview data that will be included
Creatingยป
1 2 3 4 5 6 7 | |
Updatingยป
1 2 3 4 5 6 | |
Completingยป
Two approaches:
1 2 3 4 5 | |
Cancelingยป
1 | |
Timer integrationยป
Link timers to pending events (see Scheduling documentation for more on timers):
1 2 3 4 | |
The pending event is then available in the timer handler:
1 2 3 | |
Example: Simple delayยป
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |