Skip to content

Commit 74f51a6

Browse files
committed
Add Signals documentation and update navigation in mkdocs.yml
- Introduced a new documentation file for Signals, detailing their functionality, usage, and examples for `PruneSignal` and `ReQueueAfterSignal`. - Updated mkdocs.yml to include the new Signals documentation in the navigation structure, enhancing accessibility for users.
1 parent ef84f0c commit 74f51a6

2 files changed

Lines changed: 133 additions & 0 deletions

File tree

docs/docs/exosphere/signals.md

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# Signals
2+
3+
!!! beta "Beta Feature"
4+
Signals are currently available in beta. The API and functionality may change in future releases.
5+
6+
Signals are a mechanism in Exosphere for controlling workflow execution flow and state management. They allow nodes to communicate with the state manager to perform specific actions like pruning states or requeuing them after a delay.
7+
8+
## Overview
9+
10+
Signals are implemented as exceptions that should be raised from within node execution. When a signal is raised, the runtime automatically handles the communication with the state manager to perform the requested action.
11+
12+
## Available Signals
13+
14+
### PruneSignal
15+
16+
The `PruneSignal` is used to permanently remove a state from the workflow execution. This is typically used when a node determines that the current execution path should be terminated.
17+
18+
#### Usage
19+
20+
```python
21+
from exospherehost import PruneSignal
22+
23+
class MyNode(BaseNode):
24+
class Inputs(BaseModel):
25+
data: str
26+
27+
class Outputs(BaseModel):
28+
result: str
29+
30+
async def execute(self, inputs: Inputs) -> Outputs:
31+
if inputs.data == "invalid":
32+
# Prune the state with optional data
33+
raise PruneSignal({"reason": "invalid_data", "error": "Data validation failed"})
34+
35+
return self.Outputs(result="processed")
36+
```
37+
38+
#### Parameters
39+
40+
- `data` (dict[str, Any], optional): Additional data to include with the prune operation. Defaults to an empty dictionary.
41+
42+
### ReQueueAfterSignal
43+
44+
The `ReQueueAfterSignal` is used to requeue a state for execution after a specified time delay. This is useful for implementing retry logic, scheduled tasks, or rate limiting.
45+
46+
#### Usage
47+
48+
```python
49+
from exospherehost import ReQueueAfterSignal
50+
from datetime import timedelta
51+
52+
class RetryNode(BaseNode):
53+
class Inputs(BaseModel):
54+
retry_count: int
55+
data: str
56+
57+
class Outputs(BaseModel):
58+
result: str
59+
60+
async def execute(self, inputs: Inputs) -> Outputs:
61+
if inputs.retry_count < 3:
62+
# Requeue after 5 minutes
63+
raise ReQueueAfterSignal(timedelta(minutes=5))
64+
65+
return self.Outputs(result="completed")
66+
```
67+
68+
#### Parameters
69+
70+
- `delay` (timedelta): The amount of time to wait before requeuing the state. Must be greater than 0.
71+
72+
## Important Notes
73+
74+
1. **Do not catch signals**: Signals are designed to bubble up to the runtime for handling. Do not catch these exceptions in your node code.
75+
76+
2. **Automatic handling**: The runtime automatically sends signals to the state manager when they are raised.
77+
78+
3. **State lifecycle**: Signals affect the state's lifecycle in the state manager:
79+
- `PruneSignal`: Sets state status to `PRUNED`
80+
- `ReQueueAfterSignal`: Sets state status to `CREATED` and schedules requeue
81+
82+
## Error Handling
83+
84+
If signal sending fails (e.g., network issues), the runtime will log the error and continue processing other states. The failed signal will not be retried automatically.
85+
86+
## Examples
87+
88+
### Conditional Pruning
89+
90+
```python
91+
class ValidationNode(BaseNode):
92+
class Inputs(BaseModel):
93+
user_id: str
94+
data: dict
95+
96+
async def execute(self, inputs: Inputs) -> Outputs:
97+
if not self._validate_user(inputs.user_id):
98+
raise PruneSignal({
99+
"reason": "invalid_user",
100+
"user_id": inputs.user_id,
101+
"timestamp": datetime.now().isoformat()
102+
})
103+
104+
return self.Outputs(validated=True)
105+
```
106+
107+
### Polling
108+
109+
```python
110+
class PollingNode(BaseNode):
111+
class Inputs(BaseModel):
112+
job_id: str
113+
114+
async def execute(self, inputs: Inputs) -> Outputs:
115+
# Check if the job is complete
116+
job_status = await self._check_job_status(inputs.job_id)
117+
118+
if job_status == "completed":
119+
result = await self._get_job_result(inputs.job_id)
120+
return self.Outputs(result=result)
121+
elif job_status == "failed":
122+
# Job failed, prune the state
123+
raise PruneSignal({
124+
"reason": "job_failed",
125+
"job_id": inputs.job_id,
126+
"poll_count": inputs.poll_count
127+
})
128+
else:
129+
# Job still running, poll again in 30 seconds
130+
raise ReQueueAfterSignal(timedelta(seconds=30))
131+
```

docs/mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ plugins:
103103
- exosphere/create-graph.md
104104
- exosphere/trigger-graph.md
105105
- exosphere/dashboard.md
106+
- exosphere/signals.md
106107
- exosphere/architecture.md
107108

108109
markdown_extensions:
@@ -130,4 +131,5 @@ nav:
130131
- Create Graph: exosphere/create-graph.md
131132
- Trigger Graph: exosphere/trigger-graph.md
132133
- Dashboard: exosphere/dashboard.md
134+
- Signals: exosphere/signals.md
133135
- Architecture: exosphere/architecture.md

0 commit comments

Comments
 (0)