|
1 | 1 | """The WorkflowEngine execution logic.
|
2 | 2 |
|
3 |
| -Module philosophy |
4 |
| ------------------ |
5 |
| -The module implements the workflow execution logic, which is driven by |
6 |
| -Pod and Workflow protocol buffer messages received by its 'handle_message()' function. |
7 |
| -Messages are delivered by the message handler in the PBC Pod. |
8 |
| -There are no other publci methods in this class - it's _entry point_ is |
9 |
| -'handle_message()'. |
10 |
| -
|
11 |
| -Its role is to translate a pre-validated workflow definition into the ordered execution |
12 |
| -of step "Jobs" that manifest as Pod "Instances" that run in a project directory in the |
| 3 | +This module realises workflow definitions, turning a definition into a controlled sequence |
| 4 | +of Job executions. The Data Manager is responsible for storing and validating Workflows, |
| 5 | +and this module is responsible for running them and reporting their state back to the |
13 | 6 | DM.
|
14 | 7 |
|
15 |
| -Workflow messages initiate (START) and terminate (STOP) workflows. Pod messages signal |
16 |
| -the end of individual workflow steps and carry the exit code of the executed Job. |
17 |
| -The engine used START messages to launch the first "step" in a workflow and the Pod |
18 |
| -messages to signal the success (or failure) of a prior step. A step's success is used, |
19 |
| -along with it's original workflow definition to determine the next action |
20 |
| -(run the next step or signal the end of the workflow). |
21 |
| -
|
22 |
| -Before a START message is transmitted the author (typically the Workflow Validator) |
23 |
| -will have created a RunningWorkflow record in the DM. The ID of this record is passed |
24 |
| -in the START message that is sent. The engine uses this ID to find the running workflow |
25 |
| -and the workflow. The engine creates RunningWorkflowStep records for each step that |
26 |
| -is executed, and it uses thew InstanceLauncher to launch the Job (a Pod) for each step. |
| 8 | +The engine is event-driven, responding to two types of message |
| 9 | +(in the form of Protocol Buffers) - Workflow messages and a Pod messages. |
| 10 | +These messages, sent from the DM Protocol Buffer Consumer (PBC), are delivered to the |
| 11 | +engine via its 'handle_message()' method. The engine must react to these messages |
| 12 | +appropriately by: - |
| 13 | +
|
| 14 | +- Starting the execution of a new Workflow |
| 15 | + (when it receives a Workflow 'START' message) |
| 16 | +- Stopping the execution of an exiting Workflow |
| 17 | + (when it receives a Workflow 'STOP' message) |
| 18 | +- Progressing an exiting running workflow to its next Step |
| 19 | + (when it receives a Pod message) |
| 20 | +
|
| 21 | +When running a workflow, once the engine determines the action (the Step to run) |
| 22 | +its most complex logic lies in the preparation of a set variables for the Step (Job). |
| 23 | +This logic is confined to '_prepare_step()', which returns a 'StepPreparationResponse' |
| 24 | +dataclass object. This object is used by the second key method in this module, |
| 25 | +'_launch()'. The launch methods used the prepared variables and launches (using |
| 26 | +a DM-provided 'InstanceLauncher' implementation) one or more Instances of a Step Job, |
| 27 | +providing each with an appropriate set of command variables. |
| 28 | +
|
| 29 | +Module philosophy |
| 30 | +----------------- |
| 31 | +The module's role is to translate a pre-validated workflow definition into the ordered |
| 32 | +execution of Step "Jobs" that manifest as Pod "Instances" running in a project directory |
| 33 | +under the control of the DM. |
| 34 | +
|
| 35 | +Workflow messages are used to initiate (START) and terminate (STOP) workflows. |
| 36 | +Pod messages signal the end of a previously launched step and carry the exit code |
| 37 | +of the executed Job. |
| 38 | +
|
| 39 | +The engine uses START messages to launch the first "step" in a workflow, while Pod |
| 40 | +messages signal the success (or failure) of a prior step. A step's success is used, |
| 41 | +along with it's original workflow definition to determine the next action - either |
| 42 | +the execution of a new step or the conclusion of the Workflow. |
| 43 | +
|
| 44 | +The engine does has no persistence and not create database records. Instead it relies |
| 45 | +on an API 'wrapper' to retrieve records and alter them. |
| 46 | +
|
| 47 | +Objects that provide API and InstanceLauncher implementations are made available |
| 48 | +to the engine when the DM creates it. passing them through the class initialiser. |
| 49 | +
|
| 50 | +The engine is designed not to retain any state persistence, it reacts to messages, |
| 51 | +reconstructing its state based on Workflow, RunningWorkflow, and RunningWorkflowStep |
| 52 | +records maintained by the DM. There's no real 'pattern' here - it's simply complex |
| 53 | +custom sequential logic that is executed from the context of 'handle_message()' |
| 54 | +that has to translate a workflow definition into running Job Instances. |
| 55 | +
|
| 56 | +If there is a pattern its closest approximation is probably a State pattern, closely |
| 57 | +related to a Finite State Machine with the function 'handle_message()' used to alter |
| 58 | +the engine's 'state'. The engine is in fact a complex running workflow 'state machine', |
| 59 | +hence the term 'Engine' (another term for machine) used in its class name. |
| 60 | +
|
| 61 | +Only one instance of the engine is created by the DM so it also essentially exists as a |
| 62 | +Singleton. |
| 63 | +
|
| 64 | +There are no sub-classes or other modules. Today all the state logic is captured |
| 65 | +in this single module. There is no need to introduce level of redirection that simply |
| 66 | +reduce the size of the file. There is a level of complexity that cannot be avoided - |
| 67 | +the need to understand how to move a workflow forward and how to prepare a set of |
| 68 | +variables for the next 'Step'. |
27 | 69 | """
|
28 | 70 |
|
29 | 71 | import logging
|
|
0 commit comments