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
readme: Add best practices, overview, and run explanation (#65)
* workflow: Add best practices, overview, and run explanation
* workflow: Add best practices, overview, and run explanation
* workflow: Add best practices, overview, and run explanation
* add mentioned in awesome Go
* Update README.md
Co-authored-by: Ed Harrod <echarrod@users.noreply.github.com>
* Update README.md
Co-authored-by: Ed Harrod <echarrod@users.noreply.github.com>
* Update README.md
Co-authored-by: Ed Harrod <echarrod@users.noreply.github.com>
* Update README.md
Co-authored-by: Ed Harrod <echarrod@users.noreply.github.com>
* Update README.md
Co-authored-by: Ed Harrod <echarrod@users.noreply.github.com>
* remove table of contents
* move run states to table
---------
Co-authored-by: Ed Harrod <echarrod@users.noreply.github.com>
<a style="padding: 0 5px" href="https://github.com/avelino/awesome-go"><img src="https://awesome.re/mentioned-badge-flat.svg" alt="Mentioned in Awesome Go"></a>
13
14
</div>
14
15
</div>
15
16
16
17
# Workflow
17
18
18
-
Workflow is an event driven workflow that allows for robust, durable, and scalable sequential business logic to
19
-
be executed in a deterministic manner.
19
+
**Workflow** is a distributed event driven workflow framework that runs robust, durable, and
20
+
scalable sequential business logic on your services.
21
+
22
+
**Workflow** uses a [RoleScheduler](https://github.com/luno/workflow/blob/main/rolescheduler.go) to distribute the work
23
+
across your instances through a role assignment process (similar to a leadership election process, but with more than
24
+
a single role of leader).
25
+
26
+
**Workflow** expects to be run on multiple instances but can also be run on single
27
+
instances. Using the above-mentioned [RoleScheduler](https://github.com/luno/workflow/blob/main/rolescheduler.go),
28
+
**Workflow** is able to make sure each process only runs once at any given time
29
+
regardless if you are running 40 instances of your service or 1 instance.
20
30
21
31
---
32
+
22
33
## Features
23
34
24
35
-**Tech stack agnostic:** Use Kafka, Cassandra, Redis, MongoDB, Postgresql, MySQL, RabbitM, or Reflex - the choice is yours!
25
36
-**Graph based (Directed Acyclic Graph - DAG):** Design the workflow by defining small units of work called "Steps".
26
-
-**TDD:** Workflow was built using TDD and remains well-supported through a suit of tools.
37
+
-**TDD:****Workflow** was built using TDD and remains well-supported through a suit of tools.
38
+
-**Callbacks:** Allow for manual callbacks from webhooks or manual triggers from consoles to progress the workflow, such as approval buttons or third-party webhooks.
39
+
-**Event fusion:** Add event connectors to your workflow to consume external event streams (even if it's from a different event streaming platform).
40
+
-**Hooks:** Write hooks that execute on core changes in a workflow Run.
27
41
-**Schedule:** Allows standard cron spec to schedule workflows
28
42
-**Timeouts:** Set either a dynamic or static time for a workflow to wait for. Once the timeout finishes everything continues as it was.
29
-
-**Event fusion:** Add event connectors to your workflow to consume external event streams (even if its from a different event streaming platform).
30
-
-**Callbacks:** Allow for manual callbacks from webhooks or manual triggers from consoles to progress the workflow such as approval buttons or third-party webhooks.
31
43
-**Parallel consumers:** Specify how many step consumers should run or specify the default for all consumers.
32
44
-**Consumer management:** Consumer management and graceful shutdown of all processes making sure there is no goroutine leaks!
33
45
@@ -39,9 +51,45 @@ To start using workflow you will need to add the workflow module to your project
39
51
go get github.com/luno/workflow
40
52
```
41
53
42
-
### Adapters
43
-
Some adapters dont come with the core workflow module such as `kafkastreamer`, `reflexstreamer`, `sqlstore`, and `sqltimeout`. If you
44
-
wish to use these you need to add them individually based on your needs or build out your own adapter.
54
+
---
55
+
56
+
## Adapters
57
+
Adapters enable **Workflow** to be tech stack agnostic by placing an interface /
58
+
protocol between **Workflow** and the tech stack. **Workflow**
59
+
uses adapters to understand how to use that specific tech stack.
60
+
61
+
For example, the Kafka adapter enables workflow
62
+
to produce messages to a topic as well as consume them from a topic using a set of predefined methods that wrap the
63
+
kafka client. [Reflex](https://github.com/luno/reflex) is an event streaming framework that works very differently
64
+
to Kafka and the adapter pattern allows for the differences to be contained and localised in the adapter and not
65
+
spill into the main implementation.
66
+
67
+
### Event Streamer
68
+
The [EventStreamer](https://github.com/luno/workflow/blob/main/eventstream.go) adapter interface defines what is needed
69
+
to be satisfied in order for an event streaming platform or framework to be used by **Workflow**.
70
+
71
+
All implementations of the EventStreamer interface should be tested using [adaptertest.TestEventStreamer](https://github.com/luno/workflow/blob/main/adapters/adaptertest/eventstreaming.go)
72
+
73
+
### Record Store
74
+
The [RecordStore](https://github.com/luno/workflow/blob/main/store.go) adapter interface defines what is needed to
75
+
satisfied in order for a storage solution to be used by **Workflow**.
76
+
77
+
All implementations of the RecordStore interface should be tested using [adaptertest.RunRecordStoreTest](https://github.com/luno/workflow/blob/main/adapters/adaptertest/recordstore.go)
78
+
79
+
### Role Scheduler
80
+
The [RoleScheduler](https://github.com/luno/workflow/blob/main/rolescheduler.go) adapter interface defines what is needed to
81
+
satisfied in order for a role scheduling solution to be used by **Workflow**.
82
+
83
+
All implementations of the RoleScheduler interface should be tested using [adaptertest.RunRoleSchedulerTest](https://github.com/luno/workflow/blob/main/adapters/adaptertest/rolescheduler.go)
84
+
85
+
There are more adapters available but only the above 3 are core requirements to use **Workflow**. To start, use the
86
+
in-memory implementations as that is the simplest way to experiment and get used to **Workflow**. For testing other
87
+
adapter types be sure to look at [adaptertest](https://github.com/luno/workflow/blob/main/adapters/adaptertest) which
88
+
are tests written for adapters to ensure that they meet the specification.
89
+
90
+
Adapters, except for the in-memory implementations, don't come with the core **Workflow** module such as `kafkastreamer`, `reflexstreamer`, `sqlstore`,
91
+
`sqltimeout`, `rinkrolescheduler`, `webui` and many more. If you wish to use these you need to add them individually
92
+
based on your needs or build out your own adapter.
45
93
46
94
#### Kafka
47
95
```bash
@@ -62,8 +110,32 @@ go get github.com/luno/workflow/adapters/sqlstore
62
110
```bash
63
111
go get github.com/luno/workflow/adapters/sqltimeout
64
112
```
113
+
114
+
#### Rink Role Scheduler
115
+
```bash
116
+
go get github.com/luno/workflow/adapters/rinkrolescheduler
117
+
```
118
+
119
+
#### WebUI
120
+
```bash
121
+
go get github.com/luno/workflow/adapters/webui
122
+
```
123
+
65
124
---
66
-
## Usage
125
+
126
+
## Connectors
127
+
Connectors allow **Workflow** to consume events from an event streaming platform or
128
+
framework and either trigger a workflow run or provide a callback to the workflow run. This means that Connectors can act
129
+
as a way for **Workflow** to connect with the rest of the system.
130
+
131
+
Connectors are implemented as adapters as they would share a lot of the same code as implementations of an
132
+
EventStreamer and can be seen as a subsection of an adapter.
133
+
134
+
An example can be found [here](_examples/connector).
135
+
136
+
---
137
+
138
+
## Basic Usage
67
139
68
140
### Step 1: Define the workflow
69
141
```go
@@ -171,10 +243,26 @@ Head on over to [./_examples](./_examples) to get familiar with **callbacks**, *
171
243
172
244
---
173
245
174
-
## Workflow's RunState
175
-
RunState is the state of a Run and can only exist in one state at any given time. RunState is a
176
-
finite state machine and allows for control over the Run. A Run is every instance of
177
-
a triggered workflow.
246
+
## What is a workflow Run
247
+
248
+
When a **Workflow** is triggered it creates an individual workflow instance called a Run. This is represented as workflow.Run in
249
+
**Workflow**. Each run has a lifecycle which is a finite set of states - commonly
250
+
referred to as Finite State Machine. Each
251
+
workflow Run has the following of states (called RunState in **Workflow**):
| OnPause | workflow.RunStateChangeHookFunc | error | Fired when a Run enters RunStatePaused | Yes |
221
309
| OnCancelled | workflow.RunStateChangeHookFunc | error | Fired when a Run enters RunStateCancelled | Yes |
222
-
| OnDataDeleted | workflow.RunStateChangeHookFunc | error | Fired when a Run enters RunStateDeleted | Yes |
223
310
| OnCompleted | workflow.RunStateChangeHookFunc | error | Fired when a Run enters RunStateCompleted | Yes |
224
311
225
312
---
@@ -344,6 +431,7 @@ b.AddStep(
344
431
workflow.PauseAfterErrCount(3),
345
432
)
346
433
```
434
+
347
435
---
348
436
349
437
## Glossary
@@ -364,3 +452,20 @@ b.AddStep(
364
452
| **RunState** | RunState defines the finite number of states that a Run can be in. This is used to control and monitor the lifecycle of Runs. |
365
453
| **Topic** | A method that generates a topic for producing events in the event streamer based on the workflow name and status. |
366
454
| **Trigger** | A method in the workflow API that initiates a workflow for a specified foreignID and starting status. It returns a Run ID and allows for additional configuration options. |
455
+
456
+
---
457
+
458
+
## Best practices
459
+
460
+
1. Break up complex business logic into small steps.
461
+
2. **Workflow** can be used to produce new meaningful data and not just be used to execute logic. If it is used for this, it's suggested
462
+
to implement a CQRS pattern where the workflow acts as the "Command" and the data is persisted into a more queryable manner.
463
+
3. Changes to workflows must be backwards compatible. If you need to introduce a non-backwards compatible change
464
+
then the non-backwards compatible workflow should be added alongside the existing workflow with
465
+
the non-backwards compatible workflow receiving all the incoming triggers. The old workflow should be given time
466
+
to finish processing any workflows it started and once it has finished processing all the existing non-finished Runs
467
+
then it may be safely removed. Alternatively versioning can be added internally to your Object type that you provide,
468
+
but this results in changes to the workflow's Directed Acyclic Graph (map of steps connecting together).
469
+
4. **Workflow** is not intended for low-latency. Asynchronous event driven systems are not meant to be low-latency but
470
+
prioritise decoupling, durability, distribution of workload, and breakdown of complex logic (to name a few).
471
+
5. Ensure that the prometheus metrics that come with **Workflow** are being used for monitoring and alerting.
0 commit comments