You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#### Migration notes
None
- [ ] The change comes with new or modified tests
- [ ] Hard-to-understand functions have explanatory comments
- [x] End-user documentation is updated to reflect the change
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Documentation**
- Enhanced documentation for Substantial runtime.
- Added new section on Backend operations.
- Renamed existing Backend section to "Persistence and Lifecycle."
- Introduced new subsections on workflow management concepts including
Context, Interrupts, Save, Send/Receive, and Ensure.
- Added a new section on Advanced Filters with examples for Python and
TypeScript.
- Corrected typographical errors for improved clarity.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Signed-off-by: michael-0acf4 <[email protected]>
Copy file name to clipboardExpand all lines: docs/metatype.dev/docs/reference/runtimes/substantial/index.mdx
+221-5Lines changed: 221 additions & 5 deletions
Original file line number
Diff line number
Diff line change
@@ -5,15 +5,15 @@ import TabItem from "@theme/TabItem";
5
5
6
6
## Substantial runtime
7
7
8
-
The Substantial runtime enables the execution of durable workflows in one or accross multiple typegates.
8
+
The Substantial runtime enables the execution of durable workflows in one or across multiple typegates.
9
9
10
10
Why use it?
11
11
12
12
-**Long-running "processes"**: Durable tasks that need to run over extended periods (days, weeks or months), handling **retries** and **restarts** seamlessly.
13
13
-**Fault-tolerant execution**: Ensure reliable execution of tasks, even upon failures, by maintaining a durable state of the latest run.
14
-
-**Task orchestration**: Coordinate complex sequences of workflows (analogous to microservices interactions).
14
+
-**Task orchestration**: Coordinate complex sequences of workflows (analogous to microservice interactions).
15
15
16
-
For example, the workflow bellow will continue running until a `confirmation` event is sent to the **associated run**.
16
+
For example, the workflow below will continue running until a `confirmation` event is sent to the **associated run**.
17
17
18
18
```typescript
19
19
exportasyncfunction sendEmail(ctx:Context) {
@@ -37,20 +37,233 @@ Additionally, if we were to shut down the Typegate node executing it and then re
37
37
38
38
## Key Concepts
39
39
40
+
### Backend
41
+
42
+
This abstraction implements a set of atomic operations that allows Typegate to persist and recover the workflow state. Currently, we have the **Redis** backend available, along with others like **fs** and **memory**, which are primarily intended for development or testing purposes.
43
+
40
44
### Workflows
41
45
42
46
A special type of function with **durable state** and an execution mechanism directly tied to time. A workflow can also trigger other workflows (child workflows).
43
47
44
-
###Backend
48
+
#### Persistence and Lifecycle
45
49
46
-
This abstraction implements a set of atomic operations that allows Typegate to persist and recover the workflow state. Currently, we have the **Redis** backend available, along with others like **fs** and **memory**, which are primarily intended for development or testing purposes.
50
+
-**Context**
51
+
52
+
The context object contains the workflow input (namely `kwargs` as seen in the example above), but it can also be thought as a namespace that contains all of the core functions used for durableness.
53
+
54
+
It is recreated at every replay.
55
+
56
+
-**Interrupts**
57
+
58
+
A special state of the program that is produced by any function that can trigger a workflow **replay**.
59
+
60
+
An interrupt will pause the program at the line it was emitted then queue it back to execute later.
61
+
62
+
One simple example of such function is when you want to wait for a given amount of time, Substantial will save the current time and the end time, interrupts the workflow then requeue it to execute later.
63
+
64
+
Any agent (Typegate node) that picks the workflow, will **replay** it, the cycle repeats until the actual current time is greater or equal to the end time.
65
+
66
+
```typescript
67
+
awaitctx.sleep(24*3600*1000); // 1 day
68
+
```
69
+
70
+
-**Save**
71
+
72
+
A save is one of the main building blocks of a workflow, many functions available on the context object rely on it.
73
+
74
+
This is mainly because a save call converts any function into a **durable** one: the function output is saved and persisted in the backend. On subsequent executions, the saved value is retrieved from the backend instead of re-executing the function.
75
+
76
+
This ensures that when a workflow is resumed (after a Typegate reboot for example) or replayed (after interrupts), the saved function will not be executed again.
77
+
78
+
```typescript
79
+
// For example, if the output was 7 then after replay,
80
+
// save will not execute the function inside but directly return already persisted value, which was 7.
// If you keep in mind that the workflow can be replayed many times
84
+
// A save call should make more sense!
85
+
const now =awaitctx.save(() =>Date.now());
86
+
87
+
// And even more for functions that can produce external side-effects
88
+
const result =awaitctx.save(() =>sendEmail());
89
+
```
90
+
91
+
:::info Notes
92
+
93
+
- Only JSON-compliant values can be persisted. The execution will throw otherwise.
94
+
- Make sure to not rely on changing outside references inside a save call, best is to always expect a replay.
95
+
96
+
```typescript
97
+
let value =5;
98
+
const afterSave =awaitsave(() => {
99
+
value*=2;
100
+
returnsave; // 10 will be stored on the Backend
101
+
});
102
+
103
+
console.log(value); // 10 on the first replay, 5 on the next replay (save call function was skipped)
104
+
console.log(afterSave); // always 10
105
+
106
+
// Ideally, what you want is to reuse the saved value if the effect was desired
107
+
// especially when you branch
108
+
if (afterSave==10) {
109
+
console.log("All good"); // branch path is now durable even after replays!
110
+
} else {
111
+
thrownewError("Unreachable code");
112
+
}
113
+
```
114
+
115
+
:::
116
+
117
+
-**Send/Receive**
118
+
119
+
You can send events to a workflow through GraphQL, any receive call on the workflow will await for it and will **interrupt** the workflow if it hasn't been received yet.
0 commit comments