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
Copy file name to clipboardExpand all lines: doc/workflows.md
+28-28Lines changed: 28 additions & 28 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,9 +2,9 @@
2
2
3
3
## What is a Workflow?
4
4
5
-
Workflows are resilient programs, meaning that they will continue execution even in the presence of different failure conditions.
5
+
Workflows are resilient programsthat will continue execution even under different failure conditions.
6
6
7
-
Workflows encapsulate execution/orchestration of Tasks which include Activities and child Workflows. They also need to react to external events, deal with Timeouts, etc.
7
+
Workflows encapsulate the execution/orchestration of Tasks, including Activities and child Workflows. They must also react to external events, deal with Timeouts, etc.
8
8
9
9
In this Clojure SDK programming model, a Temporal Workflow is a function declared with ([defworkflow](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.workflow#defworkflow))
10
10
@@ -16,7 +16,7 @@ In this Clojure SDK programming model, a Temporal Workflow is a function declare
16
16
17
17
## Implementing Workflows
18
18
19
-
A Workflow implementation consists of defining a (defworkflow) function. This function is invoked by the platform each time a new Workflow execution is started or retried. As soon as this method returns, the Workflow execution is considered as completed and the result is available to the caller via ([get-result](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.client.core#get-result)).
19
+
A Workflow implementation consists of defining a (defworkflow) function. The platform invokes this function each time a new Workflow execution is started or retried. Returning from the method signals that the Workflow execution is considered complete. The result is available to the caller via ([get-result](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.client.core#get-result)).
20
20
21
21
### Example
22
22
@@ -30,36 +30,36 @@ A Workflow implementation consists of defining a (defworkflow) function. This fu
30
30
31
31
### Workflow Implementation Constraints
32
32
33
-
Temporal uses the [Event Sourcing pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing) to recover the state of a Workflow object including its threads and local variable values. In essence, every time a Workflow state has to be restored, its code is re-executed from the beginning. Note that during replay, successfully executed Activities are not re-executed as their results are already recorded in the Workflow event history.
33
+
Temporal uses the [Event Sourcing pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing) to recover the state of a Workflow object, including its threads and local variable values. In essence, the Workflow code is re-executed from the beginning whenever a Workflow state requires restoration. During replay, successfully executed Activities are not re-executed but return the result previously recorded in the Workflow event history.
34
34
35
-
Even though Temporal has the replay capability, which brings resilience to your Workflows, you should never think about this capability when writing your Workflows. Instead, you should focus on implementing your business logic/requirements and write your Workflows as they would execute only once.
35
+
Even though Temporal has the replay capability, which brings resilience to your Workflows, you should never think about this capability when writing your Workflows. Instead, you should focus on implementing your business logic/requirements and write your Workflows as they would execute only once.
36
36
37
-
There are some things however to think about when writing your Workflows, namely determinism and isolation. We summarize these constraints here:
37
+
There are some things, however, to think about when writing your Workflows, namely determinism and isolation. We summarize these constraints here:
38
38
39
-
- Do not use any mutable global variables such as atoms in your Workflow implementations. This will assure that multiple Workflow instances are fully isolated.
39
+
- Do not use any mutable global variables such as atoms in your Workflow implementations. This will ensure that multiple Workflow instances are fully isolated.
40
40
- Do not call any non-deterministic functions like non-seeded random or uuid-generators directly from the Workflow code. (Coming soon: SideEffect API)
41
-
- Perform all IO operations and calls to third-party services on Activities and not Workflows, as they are usually non-deterministic in nature.
42
-
- Do not use any programming language constructs that rely on system time. (Coming soon: API methods for time)
43
-
- Do not use threading primitives such as clojure.core.async/go or clojure.core.async/thread. (Coming soon: API methods for async function execution)
41
+
- Perform all IO operations and calls to third-party services on Activities and not Workflows, as they are usually non-deterministic.
42
+
- Do not use any programming language constructs that rely on system time. (Coming soon: API methods for time)
43
+
- Do not use threading primitives such as clojure.core.async/go or clojure.core.async/thread. (Coming soon: API methods for async function execution)
44
44
- Do not perform any operations that may block the underlying thread, such as clojure.core.async/<!!.
45
-
- There is no general need in explicit synchronization because multi-threaded code inside a Workflow is executed one thread at a time and under a global lock.
46
-
- This Clojure SDK provides integration with [promesa](https://github.com/funcool/promesa) with a few limitations (See [Promises](#promises)), for asynchronous integration with safe blocking operations, such as waiting on an Activity.
47
-
- (Coming soon) Use versioning-support when making any changes to the Workflow code. Without this, any deployment of updated Workflow code might break already running Workflows.
48
-
- Don’t access configuration APIs directly from a Workflow because changes in the configuration might affect a Workflow execution path. Pass it as an argument to a Workflow function or use an Activity to load it.
45
+
- There is no general need for explicit synchronization because multi-threaded code inside a Workflow is executed one thread at a time and under a global lock.
46
+
- This Clojure SDK provides integration with [promesa](https://github.com/funcool/promesa) with a few limitations (See [Promises](#promises)) for asynchronous integration with safe blocking operations, such as waiting on an Activity.
47
+
- (Coming soon) Use versioning-support when making changes to the Workflow code. Without this, any deployment of updated Workflow code might break already running Workflows.
48
+
- Don’t access configuration APIs directly from a Workflow because changes in the configuration might affect a Workflow execution path. Pass it as an argument to a Workflow function or use an Activity to load it.
49
49
50
50
## Registering Workflows
51
51
52
-
By default, Workflows are automatically registered simply by declaring a (defworkflow). You may optionally manually declare specific Workflows to register when creating Workers (see [worker-options](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.client.worker#worker-options)).
52
+
By default, Workflows are automatically registered simply by declaring a (defworkflow). You may optionally manually specify Workflows to register when creating Workers (see [worker-options](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.client.worker#worker-options)).
53
53
54
-
*It should be noted that the name of the workflow, the arguments and signals that the workflow accepts, and the data that the workflow returns are all part of a contract that you need to maintain across potentially long-lived instances. Therefore, the Workflow definition must be treated with care whenever code is refactored.*
54
+
*It should be noted that the name of the Workflow, the arguments and signals that the Workflow accepts, and the data that the workflow returns are all part of a contract that you need to maintain across potentially long-lived instances. Therefore, refactoring code involving Workflow logic should be treated with care to avoid inadvertently breaking your contract.*
55
55
56
56
## Starting Workflow Executions
57
57
58
-
In this Clojure SDK, Workflows are always started with the following flow:
58
+
In this Clojure SDK, developers manage Workflows with the following flow:
2. Invoke [start](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.client.core#start) or [signal-with-start](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.client.core#signal-with-start). The `params` passed to these functions will be forwarded to the workflow and available as `args` in the request map of the Workflow.
62
-
3. Gather the asynchronous results with [get-result](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.client.core#get-result) which returns a promise and needs to be dereferenced.
61
+
2.Invoke [start](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.client.core#start) or [signal-with-start](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.client.core#signal-with-start). The `params` passed to these functions will be forwarded to the Workflow and available as `args` in the request map of the Workflow.
62
+
3.Gather the asynchronous results with [get-result](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.client.core#get-result), which returns a promise and requires dereferencing before the result value is realized.
63
63
64
64
### Example
65
65
@@ -75,13 +75,13 @@ In this Clojure SDK, Workflows are always started with the following flow:
75
75
76
76
## Safe blocking within Workflows
77
77
78
-
The Temporal Workflow instance behaves like a [Lightweight Process](https://en.wikipedia.org/wiki/Light-weight_process) or [Fiber](https://en.wikipedia.org/wiki/Fiber_(computer_science)). This means the system can generally support a high ratio of Workflow instances to CPUs often in the range of 1000:1 or greater. Achieving this feat requires controlling the IO in and out of the instance in a way that maximizes resource sharing. Therefore, any LWP/Fiber implementation will generally provide its own IO constructions (e.g. mailboxes, channels, promises, etc.), and Temporal is no exception.
78
+
A Temporal Workflow instance behaves like a [Lightweight Process](https://en.wikipedia.org/wiki/Light-weight_process) or [Fiber](https://en.wikipedia.org/wiki/Fiber_(computer_science)). These types of designs support a high ratio of Workflow instances to CPUs, often in the range of 1000:1 or greater. Achieving this feat requires controlling the IO in and out of the instance to maximize resource sharing. Therefore, any LWP/Fiber implementation will generally provide its own IO constructs (e.g., mailboxes, channels, promises, etc.), and Temporal is no exception.
79
79
80
80
In this Clojure SDK, this support comes in a few different flavors:
81
81
82
82
### Promises
83
83
84
-
Certain methods naturally return Workflow-safe Promises, such as invoking an Activity from a Workflow. These Workflow-safe Promises have been integrated with the [promesa](https://github.com/funcool/promesa) library. This section serves to document their use and limitations.
84
+
Specific methods naturally return Workflow-safe Promises, such as invoking an Activity from a Workflow. The Clojure SDK integrates these Workflow-safe Promises with the [promesa](https://github.com/funcool/promesa) library. This section serves to document their use and limitations.
85
85
86
86
#### Safe to use
87
87
@@ -111,7 +111,7 @@ Placing (p/resolved) (or anything else that ultimately creates a promesa promise
111
111
112
112
##### Good example
113
113
114
-
The proper method is to ensure that a Temporal native operation starts the chain
114
+
The proper method is to ensure that a Temporal native operation starts the chain.
115
115
116
116
```clojure
117
117
...
@@ -123,15 +123,15 @@ The proper method is to ensure that a Temporal native operation starts the chain
123
123
124
124
##### Watch out for implicit conversion
125
125
126
-
The following situation can lead to a failure
126
+
The following situation can lead to a failure:
127
127
128
128
```clojure
129
129
(-> (when some-condition
130
130
(a/invoke some-activity {:some"args"}))
131
131
(p/then (fn [x] ...)))
132
132
```
133
133
134
-
for situations where some-condition is `false` because promesa will cast the scalar `nil` to (p/resolved nil), thus violating the origination rule. Instead, do this:
134
+
For situations where `some-condition` is `false` because promesa will cast the scalar `nil` to (p/resolved nil), thus violating the origination rule. Instead, do this:
135
135
136
136
```clojure
137
137
...
@@ -143,19 +143,19 @@ for situations where some-condition is `false` because promesa will cast the sca
143
143
(p/then (fn [x] ...)))
144
144
```
145
145
146
-
Thus ensuring that the origination rules are met regardless of the outcome of the conditional.
146
+
Doing so ensures that the origination rules are met regardless of the outcome of the conditional.
147
147
148
148
### Await
149
149
150
-
You may use [await](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.core#await) to efficiently park the Workflow until a provided predicate evaluates to true. The predicate is evaluated at each major state transition of the Workflow.
150
+
You may use [await](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.core#await) to efficiently park the Workflow until a provided predicate evaluates to true. The Temporal platform will re-evaluate the predicate at each major state transition of the Workflow.
151
151
152
152
### Temporal Signals
153
153
154
154
Your Workflow may send or receive [signals](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.signals).
155
155
156
156
#### Receiving Signals
157
157
158
-
Your Workflow may either block waiting with signals with [<!](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.signals#%3C!) or use the non-blocking [poll](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.signals#poll). In either case, your Workflow needs to obtain the `signals` context provided in the Worklow request map.
158
+
Your Workflow may either block waiting with signals with [<!](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.signals#%3C!) or use the non-blocking [poll](https://cljdoc.org/d/io.github.manetu/temporal-sdk/CURRENT/api/temporal.signals#poll). Either way, your Workflow needs to obtain the `signals` context provided in the Workflow request map.
159
159
160
160
##### Example
161
161
@@ -164,4 +164,4 @@ Your Workflow may either block waiting with signals with [<!](https://cljdoc.org
0 commit comments