ddeutil-workflow 0.0.24__tar.gz → 0.0.26__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ddeutil_workflow-0.0.24/src/ddeutil_workflow.egg-info → ddeutil_workflow-0.0.26}/PKG-INFO +35 -55
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/README.md +34 -53
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/pyproject.toml +4 -9
- ddeutil_workflow-0.0.26/src/ddeutil/workflow/__about__.py +1 -0
- ddeutil_workflow-0.0.26/src/ddeutil/workflow/api/__init__.py +1 -0
- {ddeutil_workflow-0.0.24/src/ddeutil/workflow → ddeutil_workflow-0.0.26/src/ddeutil/workflow/api}/api.py +42 -20
- {ddeutil_workflow-0.0.24/src/ddeutil/workflow → ddeutil_workflow-0.0.26/src/ddeutil/workflow/api}/repeat.py +2 -2
- {ddeutil_workflow-0.0.24/src/ddeutil/workflow → ddeutil_workflow-0.0.26/src/ddeutil/workflow/api}/route.py +81 -62
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil/workflow/conf.py +21 -44
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil/workflow/cron.py +1 -1
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil/workflow/exceptions.py +3 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil/workflow/scheduler.py +35 -23
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil/workflow/utils.py +7 -1
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil/workflow/workflow.py +37 -20
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26/src/ddeutil_workflow.egg-info}/PKG-INFO +35 -55
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil_workflow.egg-info/SOURCES.txt +5 -5
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil_workflow.egg-info/requires.txt +0 -1
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_conf.py +24 -7
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_cron_on.py +3 -3
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_schedule.py +4 -4
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_schedule_tasks.py +12 -2
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_stage.py +1 -1
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_workflow.py +7 -7
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_workflow_poke.py +6 -4
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_workflow_release.py +6 -72
- ddeutil_workflow-0.0.26/tests/test_workflow_release_and_queue.py +77 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_workflow_schedule.py +14 -6
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_workflow_task.py +13 -4
- ddeutil_workflow-0.0.24/src/ddeutil/workflow/__about__.py +0 -1
- ddeutil_workflow-0.0.24/src/ddeutil/workflow/cli.py +0 -130
- ddeutil_workflow-0.0.24/src/ddeutil_workflow.egg-info/entry_points.txt +0 -2
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/LICENSE +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/setup.cfg +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil/workflow/__cron.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil/workflow/__init__.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil/workflow/__types.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil/workflow/job.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil/workflow/params.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil/workflow/result.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil/workflow/stage.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil_workflow.egg-info/dependency_links.txt +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/src/ddeutil_workflow.egg-info/top_level.txt +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test__cron.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test__regex.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_conf_log.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_job.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_job_exec_py.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_job_exec_strategy.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_job_strategy.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_params.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_result.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_schedule_control.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_stage_exec_bash.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_stage_exec_hook.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_stage_exec_py.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_stage_exec_trigger.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_utils.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_utils_filter.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_utils_tag.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_utils_template.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_workflow_exec.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_workflow_exec_hook.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_workflow_exec_needs.py +0 -0
- {ddeutil_workflow-0.0.24 → ddeutil_workflow-0.0.26}/tests/test_workflow_job_exec.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ddeutil-workflow
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.26
|
4
4
|
Summary: Lightweight workflow orchestration with less dependencies
|
5
5
|
Author-email: ddeutils <korawich.anu@gmail.com>
|
6
6
|
License: MIT
|
@@ -26,7 +26,6 @@ Requires-Dist: ddeutil>=0.4.3
|
|
26
26
|
Requires-Dist: ddeutil-io[toml,yaml]>=0.2.3
|
27
27
|
Requires-Dist: pydantic==2.10.4
|
28
28
|
Requires-Dist: python-dotenv==1.0.1
|
29
|
-
Requires-Dist: typer==0.15.1
|
30
29
|
Requires-Dist: schedule<2.0.0,==1.2.2
|
31
30
|
Provides-Extra: api
|
32
31
|
Requires-Dist: fastapi<1.0.0,>=0.115.0; extra == "api"
|
@@ -68,8 +67,8 @@ configuration. It called **Metadata Driven Data Workflow**.
|
|
68
67
|
> with `.yml` files and all of config file from several data orchestration framework
|
69
68
|
> tools from my experience on Data Engineer. :grimacing:
|
70
69
|
>
|
71
|
-
> Other workflow that I interest on them and pick some interested feature
|
72
|
-
> package:
|
70
|
+
> Other workflow tools that I interest on them and pick some interested feature
|
71
|
+
> implement to this package:
|
73
72
|
>
|
74
73
|
> - [Google **Workflows**](https://cloud.google.com/workflows)
|
75
74
|
> - [AWS **Step Functions**](https://aws.amazon.com/step-functions/)
|
@@ -80,23 +79,10 @@ This project need `ddeutil` and `ddeutil-io` extension namespace packages.
|
|
80
79
|
If you want to install this package with application add-ons, you should add
|
81
80
|
`app` in installation;
|
82
81
|
|
83
|
-
| Usecase
|
84
|
-
|
85
|
-
| Python
|
86
|
-
| FastAPI Server
|
87
|
-
|
88
|
-
|
89
|
-
> I added this feature to the main milestone.
|
90
|
-
>
|
91
|
-
> :egg: **Docker Images** supported:
|
92
|
-
>
|
93
|
-
> | Docker Image | Python Version | Support |
|
94
|
-
> |-----------------------------|----------------|---------|
|
95
|
-
> | ddeutil-workflow:latest | `3.9` | :x: |
|
96
|
-
> | ddeutil-workflow:python3.10 | `3.10` | :x: |
|
97
|
-
> | ddeutil-workflow:python3.11 | `3.11` | :x: |
|
98
|
-
> | ddeutil-workflow:python3.12 | `3.12` | :x: |
|
99
|
-
> | ddeutil-workflow:python3.12 | `3.13` | :x: |
|
82
|
+
| Usecase | Install Optional | Support |
|
83
|
+
|----------------|------------------------------------------|--------------------|
|
84
|
+
| Python | `pip install ddeutil-workflow` | :heavy_check_mark: |
|
85
|
+
| FastAPI Server | `pip install ddeutil-workflow[api]` | :heavy_check_mark: |
|
100
86
|
|
101
87
|
## :beers: Usage
|
102
88
|
|
@@ -113,7 +99,7 @@ use-case.
|
|
113
99
|
run-py-local:
|
114
100
|
|
115
101
|
# Validate model that use to parsing exists for template file
|
116
|
-
type: ddeutil.workflow.Workflow
|
102
|
+
type: ddeutil.workflow.workflow.Workflow
|
117
103
|
on:
|
118
104
|
# If workflow deploy to schedule, it will running every 5 minutes
|
119
105
|
# with Asia/Bangkok timezone.
|
@@ -182,35 +168,35 @@ The main configuration that use to dynamic changing with your propose of this
|
|
182
168
|
application. If any configuration values do not set yet, it will use default value
|
183
169
|
and do not raise any error to you.
|
184
170
|
|
185
|
-
| Environment | Component
|
186
|
-
|
187
|
-
| `WORKFLOW_ROOT_PATH` |
|
188
|
-
| `WORKFLOW_CORE_REGISTRY` |
|
189
|
-
| `WORKFLOW_CORE_REGISTRY_FILTER` |
|
190
|
-
| `WORKFLOW_CORE_PATH_CONF` |
|
191
|
-
| `WORKFLOW_CORE_TIMEZONE` |
|
192
|
-
| `WORKFLOW_CORE_STAGE_DEFAULT_ID` |
|
193
|
-
| `WORKFLOW_CORE_STAGE_RAISE_ERROR` |
|
194
|
-
| `WORKFLOW_CORE_JOB_DEFAULT_ID` |
|
195
|
-
| `WORKFLOW_CORE_JOB_RAISE_ERROR` |
|
196
|
-
| `WORKFLOW_CORE_MAX_NUM_POKING` |
|
197
|
-
| `WORKFLOW_CORE_MAX_JOB_PARALLEL` |
|
198
|
-
| `WORKFLOW_CORE_MAX_JOB_EXEC_TIMEOUT` |
|
199
|
-
| `WORKFLOW_CORE_MAX_CRON_PER_WORKFLOW` |
|
200
|
-
| `WORKFLOW_CORE_MAX_QUEUE_COMPLETE_HIST` |
|
201
|
-
| `WORKFLOW_CORE_GENERATE_ID_SIMPLE_MODE` |
|
202
|
-
| `WORKFLOW_LOG_DEBUG_MODE` |
|
203
|
-
| `WORKFLOW_LOG_ENABLE_WRITE` |
|
204
|
-
| `WORKFLOW_APP_MAX_PROCESS` |
|
205
|
-
| `WORKFLOW_APP_MAX_SCHEDULE_PER_PROCESS` |
|
206
|
-
| `WORKFLOW_APP_STOP_BOUNDARY_DELTA` |
|
171
|
+
| Environment | Component | Default | Description | Remark |
|
172
|
+
|:----------------------------------------|:----------:|:---------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------|--------|
|
173
|
+
| `WORKFLOW_ROOT_PATH` | Core | . | The root path of the workflow application. | |
|
174
|
+
| `WORKFLOW_CORE_REGISTRY` | Core | src,src.ddeutil.workflow,tests,tests.utils | List of importable string for the hook stage. | |
|
175
|
+
| `WORKFLOW_CORE_REGISTRY_FILTER` | Core | src.ddeutil.workflow.utils,ddeutil.workflow.utils | List of importable string for the filter template. | |
|
176
|
+
| `WORKFLOW_CORE_PATH_CONF` | Core | conf | The config path that keep all template `.yaml` files. | |
|
177
|
+
| `WORKFLOW_CORE_TIMEZONE` | Core | Asia/Bangkok | A Timezone string value that will pass to `ZoneInfo` object. | |
|
178
|
+
| `WORKFLOW_CORE_STAGE_DEFAULT_ID` | Core | true | A flag that enable default stage ID that use for catch an execution output. | |
|
179
|
+
| `WORKFLOW_CORE_STAGE_RAISE_ERROR` | Core | false | A flag that all stage raise StageException from stage execution. | |
|
180
|
+
| `WORKFLOW_CORE_JOB_DEFAULT_ID` | Core | false | A flag that enable default job ID that use for catch an execution output. The ID that use will be sequence number. | |
|
181
|
+
| `WORKFLOW_CORE_JOB_RAISE_ERROR` | Core | true | A flag that all job raise JobException from job strategy execution. | |
|
182
|
+
| `WORKFLOW_CORE_MAX_NUM_POKING` | Core | 4 | . | |
|
183
|
+
| `WORKFLOW_CORE_MAX_JOB_PARALLEL` | Core | 2 | The maximum job number that able to run parallel in workflow executor. | |
|
184
|
+
| `WORKFLOW_CORE_MAX_JOB_EXEC_TIMEOUT` | Core | 600 | | |
|
185
|
+
| `WORKFLOW_CORE_MAX_CRON_PER_WORKFLOW` | Core | 5 | | |
|
186
|
+
| `WORKFLOW_CORE_MAX_QUEUE_COMPLETE_HIST` | Core | 16 | | |
|
187
|
+
| `WORKFLOW_CORE_GENERATE_ID_SIMPLE_MODE` | Core | true | A flog that enable generating ID with `md5` algorithm. | |
|
188
|
+
| `WORKFLOW_LOG_DEBUG_MODE` | Log | true | A flag that enable logging with debug level mode. | |
|
189
|
+
| `WORKFLOW_LOG_ENABLE_WRITE` | Log | true | A flag that enable logging object saving log to its destination. | |
|
190
|
+
| `WORKFLOW_APP_MAX_PROCESS` | Schedule | 2 | The maximum process worker number that run in scheduler app module. | |
|
191
|
+
| `WORKFLOW_APP_MAX_SCHEDULE_PER_PROCESS` | Schedule | 100 | A schedule per process that run parallel. | |
|
192
|
+
| `WORKFLOW_APP_STOP_BOUNDARY_DELTA` | Schedule | '{"minutes": 5, "seconds": 20}' | A time delta value that use to stop scheduler app in json string format. | |
|
207
193
|
|
208
194
|
**API Application**:
|
209
195
|
|
210
|
-
| Environment |
|
211
|
-
|
212
|
-
| `WORKFLOW_API_ENABLE_ROUTE_WORKFLOW` |
|
213
|
-
| `WORKFLOW_API_ENABLE_ROUTE_SCHEDULE` |
|
196
|
+
| Environment | Component | Default | Description | Remark |
|
197
|
+
|:--------------------------------------|:-----------:|---------|------------------------------------------------------------------------------------|--------|
|
198
|
+
| `WORKFLOW_API_ENABLE_ROUTE_WORKFLOW` | API | true | A flag that enable workflow route to manage execute manually and workflow logging. | |
|
199
|
+
| `WORKFLOW_API_ENABLE_ROUTE_SCHEDULE` | API | true | A flag that enable run scheduler. | |
|
214
200
|
|
215
201
|
## :rocket: Deployment
|
216
202
|
|
@@ -218,12 +204,6 @@ This package able to run as a application service for receive manual trigger
|
|
218
204
|
from the master node via RestAPI or use to be Scheduler background service
|
219
205
|
like crontab job but via Python API.
|
220
206
|
|
221
|
-
### Schedule App
|
222
|
-
|
223
|
-
```shell
|
224
|
-
(venv) $ ddeutil-workflow schedule
|
225
|
-
```
|
226
|
-
|
227
207
|
### API Server
|
228
208
|
|
229
209
|
```shell
|
@@ -231,7 +211,7 @@ like crontab job but via Python API.
|
|
231
211
|
```
|
232
212
|
|
233
213
|
> [!NOTE]
|
234
|
-
> If this package already deploy, it able to use
|
214
|
+
> If this package already deploy, it able to use multiprocess;
|
235
215
|
> `uvicorn ddeutil.workflow.api:app --host 127.0.0.1 --port 80 --workers 4`
|
236
216
|
|
237
217
|
### Docker Container
|
@@ -35,8 +35,8 @@ configuration. It called **Metadata Driven Data Workflow**.
|
|
35
35
|
> with `.yml` files and all of config file from several data orchestration framework
|
36
36
|
> tools from my experience on Data Engineer. :grimacing:
|
37
37
|
>
|
38
|
-
> Other workflow that I interest on them and pick some interested feature
|
39
|
-
> package:
|
38
|
+
> Other workflow tools that I interest on them and pick some interested feature
|
39
|
+
> implement to this package:
|
40
40
|
>
|
41
41
|
> - [Google **Workflows**](https://cloud.google.com/workflows)
|
42
42
|
> - [AWS **Step Functions**](https://aws.amazon.com/step-functions/)
|
@@ -47,23 +47,10 @@ This project need `ddeutil` and `ddeutil-io` extension namespace packages.
|
|
47
47
|
If you want to install this package with application add-ons, you should add
|
48
48
|
`app` in installation;
|
49
49
|
|
50
|
-
| Usecase
|
51
|
-
|
52
|
-
| Python
|
53
|
-
| FastAPI Server
|
54
|
-
|
55
|
-
|
56
|
-
> I added this feature to the main milestone.
|
57
|
-
>
|
58
|
-
> :egg: **Docker Images** supported:
|
59
|
-
>
|
60
|
-
> | Docker Image | Python Version | Support |
|
61
|
-
> |-----------------------------|----------------|---------|
|
62
|
-
> | ddeutil-workflow:latest | `3.9` | :x: |
|
63
|
-
> | ddeutil-workflow:python3.10 | `3.10` | :x: |
|
64
|
-
> | ddeutil-workflow:python3.11 | `3.11` | :x: |
|
65
|
-
> | ddeutil-workflow:python3.12 | `3.12` | :x: |
|
66
|
-
> | ddeutil-workflow:python3.12 | `3.13` | :x: |
|
50
|
+
| Usecase | Install Optional | Support |
|
51
|
+
|----------------|------------------------------------------|--------------------|
|
52
|
+
| Python | `pip install ddeutil-workflow` | :heavy_check_mark: |
|
53
|
+
| FastAPI Server | `pip install ddeutil-workflow[api]` | :heavy_check_mark: |
|
67
54
|
|
68
55
|
## :beers: Usage
|
69
56
|
|
@@ -80,7 +67,7 @@ use-case.
|
|
80
67
|
run-py-local:
|
81
68
|
|
82
69
|
# Validate model that use to parsing exists for template file
|
83
|
-
type: ddeutil.workflow.Workflow
|
70
|
+
type: ddeutil.workflow.workflow.Workflow
|
84
71
|
on:
|
85
72
|
# If workflow deploy to schedule, it will running every 5 minutes
|
86
73
|
# with Asia/Bangkok timezone.
|
@@ -149,35 +136,35 @@ The main configuration that use to dynamic changing with your propose of this
|
|
149
136
|
application. If any configuration values do not set yet, it will use default value
|
150
137
|
and do not raise any error to you.
|
151
138
|
|
152
|
-
| Environment | Component
|
153
|
-
|
154
|
-
| `WORKFLOW_ROOT_PATH` |
|
155
|
-
| `WORKFLOW_CORE_REGISTRY` |
|
156
|
-
| `WORKFLOW_CORE_REGISTRY_FILTER` |
|
157
|
-
| `WORKFLOW_CORE_PATH_CONF` |
|
158
|
-
| `WORKFLOW_CORE_TIMEZONE` |
|
159
|
-
| `WORKFLOW_CORE_STAGE_DEFAULT_ID` |
|
160
|
-
| `WORKFLOW_CORE_STAGE_RAISE_ERROR` |
|
161
|
-
| `WORKFLOW_CORE_JOB_DEFAULT_ID` |
|
162
|
-
| `WORKFLOW_CORE_JOB_RAISE_ERROR` |
|
163
|
-
| `WORKFLOW_CORE_MAX_NUM_POKING` |
|
164
|
-
| `WORKFLOW_CORE_MAX_JOB_PARALLEL` |
|
165
|
-
| `WORKFLOW_CORE_MAX_JOB_EXEC_TIMEOUT` |
|
166
|
-
| `WORKFLOW_CORE_MAX_CRON_PER_WORKFLOW` |
|
167
|
-
| `WORKFLOW_CORE_MAX_QUEUE_COMPLETE_HIST` |
|
168
|
-
| `WORKFLOW_CORE_GENERATE_ID_SIMPLE_MODE` |
|
169
|
-
| `WORKFLOW_LOG_DEBUG_MODE` |
|
170
|
-
| `WORKFLOW_LOG_ENABLE_WRITE` |
|
171
|
-
| `WORKFLOW_APP_MAX_PROCESS` |
|
172
|
-
| `WORKFLOW_APP_MAX_SCHEDULE_PER_PROCESS` |
|
173
|
-
| `WORKFLOW_APP_STOP_BOUNDARY_DELTA` |
|
139
|
+
| Environment | Component | Default | Description | Remark |
|
140
|
+
|:----------------------------------------|:----------:|:---------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------|--------|
|
141
|
+
| `WORKFLOW_ROOT_PATH` | Core | . | The root path of the workflow application. | |
|
142
|
+
| `WORKFLOW_CORE_REGISTRY` | Core | src,src.ddeutil.workflow,tests,tests.utils | List of importable string for the hook stage. | |
|
143
|
+
| `WORKFLOW_CORE_REGISTRY_FILTER` | Core | src.ddeutil.workflow.utils,ddeutil.workflow.utils | List of importable string for the filter template. | |
|
144
|
+
| `WORKFLOW_CORE_PATH_CONF` | Core | conf | The config path that keep all template `.yaml` files. | |
|
145
|
+
| `WORKFLOW_CORE_TIMEZONE` | Core | Asia/Bangkok | A Timezone string value that will pass to `ZoneInfo` object. | |
|
146
|
+
| `WORKFLOW_CORE_STAGE_DEFAULT_ID` | Core | true | A flag that enable default stage ID that use for catch an execution output. | |
|
147
|
+
| `WORKFLOW_CORE_STAGE_RAISE_ERROR` | Core | false | A flag that all stage raise StageException from stage execution. | |
|
148
|
+
| `WORKFLOW_CORE_JOB_DEFAULT_ID` | Core | false | A flag that enable default job ID that use for catch an execution output. The ID that use will be sequence number. | |
|
149
|
+
| `WORKFLOW_CORE_JOB_RAISE_ERROR` | Core | true | A flag that all job raise JobException from job strategy execution. | |
|
150
|
+
| `WORKFLOW_CORE_MAX_NUM_POKING` | Core | 4 | . | |
|
151
|
+
| `WORKFLOW_CORE_MAX_JOB_PARALLEL` | Core | 2 | The maximum job number that able to run parallel in workflow executor. | |
|
152
|
+
| `WORKFLOW_CORE_MAX_JOB_EXEC_TIMEOUT` | Core | 600 | | |
|
153
|
+
| `WORKFLOW_CORE_MAX_CRON_PER_WORKFLOW` | Core | 5 | | |
|
154
|
+
| `WORKFLOW_CORE_MAX_QUEUE_COMPLETE_HIST` | Core | 16 | | |
|
155
|
+
| `WORKFLOW_CORE_GENERATE_ID_SIMPLE_MODE` | Core | true | A flog that enable generating ID with `md5` algorithm. | |
|
156
|
+
| `WORKFLOW_LOG_DEBUG_MODE` | Log | true | A flag that enable logging with debug level mode. | |
|
157
|
+
| `WORKFLOW_LOG_ENABLE_WRITE` | Log | true | A flag that enable logging object saving log to its destination. | |
|
158
|
+
| `WORKFLOW_APP_MAX_PROCESS` | Schedule | 2 | The maximum process worker number that run in scheduler app module. | |
|
159
|
+
| `WORKFLOW_APP_MAX_SCHEDULE_PER_PROCESS` | Schedule | 100 | A schedule per process that run parallel. | |
|
160
|
+
| `WORKFLOW_APP_STOP_BOUNDARY_DELTA` | Schedule | '{"minutes": 5, "seconds": 20}' | A time delta value that use to stop scheduler app in json string format. | |
|
174
161
|
|
175
162
|
**API Application**:
|
176
163
|
|
177
|
-
| Environment |
|
178
|
-
|
179
|
-
| `WORKFLOW_API_ENABLE_ROUTE_WORKFLOW` |
|
180
|
-
| `WORKFLOW_API_ENABLE_ROUTE_SCHEDULE` |
|
164
|
+
| Environment | Component | Default | Description | Remark |
|
165
|
+
|:--------------------------------------|:-----------:|---------|------------------------------------------------------------------------------------|--------|
|
166
|
+
| `WORKFLOW_API_ENABLE_ROUTE_WORKFLOW` | API | true | A flag that enable workflow route to manage execute manually and workflow logging. | |
|
167
|
+
| `WORKFLOW_API_ENABLE_ROUTE_SCHEDULE` | API | true | A flag that enable run scheduler. | |
|
181
168
|
|
182
169
|
## :rocket: Deployment
|
183
170
|
|
@@ -185,12 +172,6 @@ This package able to run as a application service for receive manual trigger
|
|
185
172
|
from the master node via RestAPI or use to be Scheduler background service
|
186
173
|
like crontab job but via Python API.
|
187
174
|
|
188
|
-
### Schedule App
|
189
|
-
|
190
|
-
```shell
|
191
|
-
(venv) $ ddeutil-workflow schedule
|
192
|
-
```
|
193
|
-
|
194
175
|
### API Server
|
195
176
|
|
196
177
|
```shell
|
@@ -198,7 +179,7 @@ like crontab job but via Python API.
|
|
198
179
|
```
|
199
180
|
|
200
181
|
> [!NOTE]
|
201
|
-
> If this package already deploy, it able to use
|
182
|
+
> If this package already deploy, it able to use multiprocess;
|
202
183
|
> `uvicorn ddeutil.workflow.api:app --host 127.0.0.1 --port 80 --workers 4`
|
203
184
|
|
204
185
|
### Docker Container
|
@@ -30,7 +30,6 @@ dependencies = [
|
|
30
30
|
"ddeutil-io[yaml,toml]>=0.2.3",
|
31
31
|
"pydantic==2.10.4",
|
32
32
|
"python-dotenv==1.0.1",
|
33
|
-
"typer==0.15.1",
|
34
33
|
"schedule==1.2.2,<2.0.0",
|
35
34
|
]
|
36
35
|
dynamic = ["version"]
|
@@ -44,9 +43,6 @@ api = [
|
|
44
43
|
Homepage = "https://github.com/ddeutils/ddeutil-workflow/"
|
45
44
|
"Source Code" = "https://github.com/ddeutils/ddeutil-workflow/"
|
46
45
|
|
47
|
-
[project.scripts]
|
48
|
-
ddeutil-workflow = "ddeutil.workflow.cli:cli"
|
49
|
-
|
50
46
|
[tool.setuptools.dynamic]
|
51
47
|
version = {attr = "ddeutil.workflow.__about__.__version__"}
|
52
48
|
|
@@ -65,11 +61,10 @@ source = ["ddeutil.workflow"]
|
|
65
61
|
omit = [
|
66
62
|
"src/ddeutil/workflow/__about__.py",
|
67
63
|
"src/ddeutil/workflow/__cron.py",
|
68
|
-
|
69
|
-
"src/ddeutil/workflow/api.py",
|
70
|
-
"src/ddeutil/workflow/
|
71
|
-
"src/ddeutil/workflow/
|
72
|
-
"src/ddeutil/workflow/route.py",
|
64
|
+
"src/ddeutil/workflow/api/__init__.py",
|
65
|
+
"src/ddeutil/workflow/api/api.py",
|
66
|
+
"src/ddeutil/workflow/api/repeat.py",
|
67
|
+
"src/ddeutil/workflow/api/route.py",
|
73
68
|
]
|
74
69
|
|
75
70
|
[tool.coverage.report]
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__: str = "0.0.26"
|
@@ -0,0 +1 @@
|
|
1
|
+
from .api import app
|
@@ -11,7 +11,6 @@ import uuid
|
|
11
11
|
from collections.abc import AsyncIterator
|
12
12
|
from datetime import datetime, timedelta
|
13
13
|
from queue import Empty, Queue
|
14
|
-
from threading import Thread
|
15
14
|
from typing import TypedDict
|
16
15
|
|
17
16
|
from dotenv import load_dotenv
|
@@ -20,34 +19,39 @@ from fastapi.middleware.gzip import GZipMiddleware
|
|
20
19
|
from fastapi.responses import UJSONResponse
|
21
20
|
from pydantic import BaseModel
|
22
21
|
|
23
|
-
from
|
24
|
-
from
|
22
|
+
from ..__about__ import __version__
|
23
|
+
from ..conf import config, get_logger
|
24
|
+
from ..scheduler import ReleaseThread, ReleaseThreads
|
25
|
+
from ..workflow import WorkflowQueue, WorkflowTask
|
25
26
|
from .repeat import repeat_at, repeat_every
|
26
|
-
from .workflow import WorkflowTask
|
27
27
|
|
28
28
|
load_dotenv()
|
29
29
|
logger = get_logger("ddeutil.workflow")
|
30
30
|
|
31
31
|
|
32
32
|
class State(TypedDict):
|
33
|
+
"""TypeDict for State of FastAPI application."""
|
34
|
+
|
35
|
+
# NOTE: For upper queue route.
|
33
36
|
upper_queue: Queue
|
34
37
|
upper_result: dict[str, str]
|
38
|
+
|
39
|
+
# NOTE: For schedule listener.
|
35
40
|
scheduler: list[str]
|
36
|
-
workflow_threads:
|
41
|
+
workflow_threads: ReleaseThreads
|
37
42
|
workflow_tasks: list[WorkflowTask]
|
38
|
-
workflow_queue: dict[str,
|
39
|
-
workflow_running: dict[str, list[datetime]]
|
43
|
+
workflow_queue: dict[str, WorkflowQueue]
|
40
44
|
|
41
45
|
|
42
46
|
@contextlib.asynccontextmanager
|
43
47
|
async def lifespan(a: FastAPI) -> AsyncIterator[State]:
|
48
|
+
"""Lifespan function for the FastAPI application."""
|
44
49
|
a.state.upper_queue = Queue()
|
45
50
|
a.state.upper_result = {}
|
46
51
|
a.state.scheduler = []
|
47
52
|
a.state.workflow_threads = {}
|
48
53
|
a.state.workflow_tasks = []
|
49
54
|
a.state.workflow_queue = {}
|
50
|
-
a.state.workflow_running = {}
|
51
55
|
|
52
56
|
await asyncio.create_task(broker_upper_messages())
|
53
57
|
|
@@ -65,7 +69,6 @@ async def lifespan(a: FastAPI) -> AsyncIterator[State]:
|
|
65
69
|
#
|
66
70
|
"scheduler": a.state.scheduler,
|
67
71
|
"workflow_queue": a.state.workflow_queue,
|
68
|
-
"workflow_running": a.state.workflow_running,
|
69
72
|
"workflow_threads": a.state.workflow_threads,
|
70
73
|
"workflow_tasks": a.state.workflow_tasks,
|
71
74
|
}
|
@@ -114,12 +117,11 @@ async def get_result(request_id: str) -> dict[str, str]:
|
|
114
117
|
|
115
118
|
|
116
119
|
@app.get("/")
|
117
|
-
@app.get("/api")
|
118
120
|
async def health():
|
119
121
|
return {"message": "Workflow API already start up"}
|
120
122
|
|
121
123
|
|
122
|
-
@app.post("/
|
124
|
+
@app.post(f"{config.prefix_path}/upper")
|
123
125
|
async def message_upper(payload: Payload):
|
124
126
|
"""Convert message from any case to the upper case."""
|
125
127
|
request_id: str = str(uuid.uuid4())
|
@@ -129,27 +131,47 @@ async def message_upper(payload: Payload):
|
|
129
131
|
return await get_result(request_id)
|
130
132
|
|
131
133
|
|
134
|
+
# NOTE: Enable the workflow route.
|
132
135
|
if config.enable_route_workflow:
|
133
|
-
from .route import
|
136
|
+
from .route import workflow_route
|
137
|
+
|
138
|
+
app.include_router(workflow_route, prefix=config.prefix_path)
|
134
139
|
|
135
|
-
app.include_router(workflow)
|
136
140
|
|
141
|
+
# NOTE: Enable the schedule route.
|
137
142
|
if config.enable_route_schedule:
|
138
|
-
from
|
139
|
-
from
|
143
|
+
from ..conf import FileLog
|
144
|
+
from ..scheduler import schedule_task
|
145
|
+
from .route import schedule_route
|
140
146
|
|
141
|
-
app.include_router(
|
147
|
+
app.include_router(schedule_route, prefix=config.prefix_path)
|
142
148
|
|
143
|
-
@
|
149
|
+
@schedule_route.on_event("startup")
|
144
150
|
@repeat_at(cron="* * * * *", delay=2)
|
145
|
-
def
|
151
|
+
def scheduler_listener():
|
152
|
+
"""Schedule broker every minute at 02 second."""
|
146
153
|
logger.debug(
|
147
154
|
f"[SCHEDULER]: Start listening schedule from queue "
|
148
155
|
f"{app.state.scheduler}"
|
149
156
|
)
|
150
157
|
if app.state.workflow_tasks:
|
151
|
-
|
158
|
+
schedule_task(
|
152
159
|
app.state.workflow_tasks,
|
153
|
-
stop=datetime.now() + timedelta(minutes=1),
|
160
|
+
stop=datetime.now(config.tz) + timedelta(minutes=1),
|
161
|
+
queue=app.state.workflow_queue,
|
154
162
|
threads=app.state.workflow_threads,
|
163
|
+
log=FileLog,
|
155
164
|
)
|
165
|
+
|
166
|
+
@schedule_route.on_event("startup")
|
167
|
+
@repeat_at(cron="*/5 * * * *")
|
168
|
+
def monitoring():
|
169
|
+
logger.debug("[MONITOR]: Start monitoring threading.")
|
170
|
+
snapshot_threads: list[str] = list(app.state.workflow_threads.keys())
|
171
|
+
for t_name in snapshot_threads:
|
172
|
+
|
173
|
+
thread_release: ReleaseThread = app.state.workflow_threads[t_name]
|
174
|
+
|
175
|
+
# NOTE: remove the thread that running success.
|
176
|
+
if not thread_release["thread"].is_alive():
|
177
|
+
app.state.workflow_threads.pop(t_name)
|
@@ -12,8 +12,8 @@ from functools import wraps
|
|
12
12
|
|
13
13
|
from starlette.concurrency import run_in_threadpool
|
14
14
|
|
15
|
-
from
|
16
|
-
from
|
15
|
+
from ..__cron import CronJob
|
16
|
+
from ..conf import config, get_logger
|
17
17
|
|
18
18
|
logger = get_logger("ddeutil.workflow")
|
19
19
|
|