Repository navigation
feat: delay in next node #588
Copy link
Copy link
Open
Description
In graph config allow user to specify delay, next state would be queued after specified delay.
Motivation
- Workflow pacing – Many workflows need delays between steps (e.g., rate limiting, waiting for external systems, cooling-off periods).
- Time-based orchestration – Enable workflows with built-in timing without requiring nodes to raise
ReQueueAfterSignal. - Declarative delays – Configure delays at graph definition time rather than in node code, improving separation of concerns.
- Batch processing – Add delays between batch operations to avoid overwhelming downstream systems.
Current State
What Exists
| Component | Location | Purpose |
|---|---|---|
next_nodes |
GraphNodeModel / NodeTemplate |
List of node identifiers to execute next |
enqueue_after |
State model |
Timestamp (ms) when state should be enqueued |
create_next_states |
state-manager/app/tasks/create_next_states.py |
Creates next states when current state completes |
ReQueueAfterSignal |
python-sdk/exospherehost/signals.py |
Programmatic delay via exception (requires node code changes) |
Current Limitations
- No way to specify delays in graph configuration
- Must use
ReQueueAfterSignalin node code to add delays - Delays are not visible in graph definition
- Cannot configure different delays for different next nodes from the same node
Proposed Solution
Delay Configuration per Next Node
Allow specifying a delay for each next node connection in the graph configuration. When a state completes, the next states will be created with enqueue_after set to current time + delay.
Key Features
- Per-edge delays – Configure delay for each
next_nodesentry - Flexible delay format – Support milliseconds (integer) or human-readable strings (e.g., "5m", "1h", "30s")
- Backward compatibility – If no delay specified, next states are enqueued immediately (current behavior)
- Multiple next nodes – Each next node can have its own delay
Proposed Design
Data Model
Graph Node Configuration:
Current structure:
{
"node_name": "DataLoader",
"identifier": "loader",
"next_nodes": ["processor", "validator"]
}Proposed structure:
{
"node_name": "DataLoader",
"identifier": "loader",
"next_nodes": ["processor", "validator"],
"next_node_delays": {
"processor": 5000,
"validator": 10000
}
}Alternative: Delay as part of next_nodes mapping
{
"node_name": "DataLoader",
"identifier": "loader",
"next_nodes": {
"processor": {"delay": 5000},
"validator": {"delay": 10000}
}
}Recommended: Separate field for backward compatibility
Control Flow
flowchart TD
A["State completes successfully"] --> B["create_next_states() called"]
B --> C["Get next_node_identifiers from template"]
C --> D["For each next_node"]
D --> E{"Delay configured?"}
E -->|yes| F["Calculate enqueue_after = now + delay"]
E -->|no| G["enqueue_after = now (immediate)"]
F --> H["Create State with enqueue_after"]
G --> H
H --> I["State will be enqueued at enqueue_after time"]
Acceptance Criteria
-
GraphNodeModelsupportsnext_node_delaysfield (optional dict) -
NodeTemplatesupportsnext_node_delaysfield (optional dict) - Validation: delay values must be non-negative integers
- Validation: delay keys must match valid next_node identifiers
-
create_next_statesapplies delays when creating next states - States with delays have correct
enqueue_aftertimestamp - Backward compatibility: graphs without delays work as before
- Unit tests for delay application logic
- Integration tests for end-to-end delay flow
- Documentation updated in
docs/exosphere/graph-components.md
Engineering Tasks
-
Python SDK:
- Add
next_node_delaysfield toGraphNodeModelinexospherehost/models.py - Add validation for delay values (non-negative integers)
- Add validation that delay keys match
next_nodesidentifiers
- Add
-
State Manager:
- Add
next_node_delaysfield toNodeTemplateinapp/models/node_template_model.py - Update
create_next_statesto apply delays when creating states - Validate delay keys exist in
next_nodesduring graph validation
- Add
-
Testing:
- Unit tests for delay validation
- Integration tests for delayed state creation
- Test backward compatibility (no delays specified)
- Test multiple next nodes with different delays
-
Documentation:
- Update
docs/exosphere/graph-components.mdwith delay configuration - Add examples showing delay usage
- Document delay behavior and timing
- Update
Risks & Mitigations
| Risk | Mitigation |
|---|---|
| Breaking change for existing graphs | Make next_node_delays optional, default to immediate enqueue (backward compatible) |
| Invalid delay keys (typos, removed nodes) | Validate during graph validation, reject invalid graphs |
| Negative delays causing immediate execution | Validate delays are non-negative during graph creation |
| Very large delays causing states to be enqueued far in future | Consider max delay limit (e.g., 1 year) or document behavior |
| Delay precision confusion | Document that delays are in milliseconds, show examples |
Open Questions
- Delay format: Should we support human-readable strings (e.g., "5m", "1h") in addition to milliseconds?
- Maximum delay: Should there be a maximum delay cap to prevent accidental long-term scheduling?
- Delay validation: Should delays be validated at graph creation time or state creation time?
- Dashboard UI: How should delays be displayed in the graph visualization?
- Absolute vs relative: Should we support absolute timestamps (like
RequeueAtSignal) in addition to relative delays?
Additional Notes
- This feature complements
ReQueueAfterSignal- use graph-level delays for declarative timing, signal-based delays for dynamic timing - Delays are applied at state creation time, not at node execution time
- Consider future enhancement: delay expressions based on node outputs (e.g., delay based on data size)
- Aligns with feature-plan feat: RequeueAtSignal #587 (RequeueAtSignal) - both provide timing control but at different levels
Reactions are currently unavailable
Activity
[-]feat req: delay in next node[/-][+]feat: delay in next node[/+]