simpleflow 0.34.0__tar.gz → 0.34.2__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.
- {simpleflow-0.34.0 → simpleflow-0.34.2}/PKG-INFO +2 -27
- {simpleflow-0.34.0 → simpleflow-0.34.2}/pyproject.toml +43 -32
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/__init__.py +1 -1
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/command.py +51 -18
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/dispatch/dynamic_dispatcher.py +3 -3
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/history.py +117 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/local/executor.py +3 -4
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/metrology.py +23 -31
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/process/_supervisor.py +1 -1
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/executor.py +19 -16
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/helpers.py +16 -2
- simpleflow-0.34.2/simpleflow/swf/mapper/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/base.py +8 -10
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/event/base.py +1 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/event/workflow.py +34 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/workflow.py +1 -1
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/querysets/activity.py +1 -1
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/querysets/workflow.py +1 -1
- simpleflow-0.34.2/simpleflow/swf/process/decider/helpers.py +111 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/process/worker/base.py +1 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/stats/pretty.py +6 -2
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/task.py +1 -2
- simpleflow-0.34.0/simpleflow/main.py +0 -17
- simpleflow-0.34.0/simpleflow/swf/process/decider/helpers.py +0 -154
- {simpleflow-0.34.0 → simpleflow-0.34.2}/.gitignore +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/LICENSE +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/README.md +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/__main__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/_decorators.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/activity.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/base.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/boto3_utils.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/canvas.py +0 -0
- /simpleflow-0.34.0/simpleflow/job/__init__.py → /simpleflow-0.34.2/simpleflow/cli/workflow.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/constants.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/dispatch/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/dispatch/by_module.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/dispatch/dry_run.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/dispatch/exceptions.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/dispatch/from_task_registry.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/download.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/exceptions.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/execute.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/executor.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/format.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/futures.py +0 -0
- {simpleflow-0.34.0/simpleflow/step → simpleflow-0.34.2/simpleflow/job}/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/local/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/log.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/logging_context.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/marker.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/process/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/process/_named_mixin.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/registry.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/runtime/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/settings/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/settings/base.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/settings/default.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/signal.py +0 -0
- {simpleflow-0.34.0/simpleflow/swf → simpleflow-0.34.2/simpleflow/step}/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/step/constants.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/step/submittable.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/step/tasks.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/step/utils.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/step/workflow.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/storage.py +0 -0
- {simpleflow-0.34.0/simpleflow/swf/mapper → simpleflow-0.34.2/simpleflow/swf}/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/constants.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/actors/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/actors/core.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/actors/decider.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/actors/worker.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/constants.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/core.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/exceptions.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/activity.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/decision/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/decision/base.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/decision/marker.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/decision/task.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/decision/timer.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/decision/workflow.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/domain.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/event/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/event/compiler.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/event/factory.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/event/marker.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/event/task.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/event/timer.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/history/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/history/base.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/models/history/builder.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/querysets/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/querysets/base.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/querysets/domain.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/querysets/history.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/responses/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/responses/_base.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/settings.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/mapper/utils.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/process/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/process/decider/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/process/decider/base.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/process/decider/command.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/process/poller.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/process/worker/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/process/worker/command.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/stats/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/stats/base.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/task.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/swf/utils.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/utils/__init__.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/utils/_dict.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/utils/_json.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/utils/retry.py +0 -0
- {simpleflow-0.34.0 → simpleflow-0.34.2}/simpleflow/workflow.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simpleflow
|
|
3
|
-
Version: 0.34.
|
|
3
|
+
Version: 0.34.2
|
|
4
4
|
Summary: Python library for dataflow programming with Amazon SWF
|
|
5
5
|
Project-URL: documentation, https://botify-labs.github.io/simpleflow
|
|
6
6
|
Project-URL: repository, https://github.com/botify-labs/simpleflow
|
|
7
7
|
Project-URL: changelog, https://github.com/botify-labs/simpleflow/blob/main/CHANGELOG.md
|
|
8
8
|
Author: Greg Leclercq
|
|
9
9
|
Maintainer-email: tech@botify.com
|
|
10
|
-
License: MIT
|
|
10
|
+
License-Expression: MIT
|
|
11
11
|
License-File: LICENSE
|
|
12
12
|
Keywords: amazon swf,simple workflow,simpleflow
|
|
13
13
|
Classifier: Development Status :: 4 - Beta
|
|
@@ -37,31 +37,6 @@ Requires-Dist: psutil
|
|
|
37
37
|
Requires-Dist: pytz
|
|
38
38
|
Requires-Dist: setproctitle
|
|
39
39
|
Requires-Dist: tabulate<1.0.0,>=0.8.2
|
|
40
|
-
Provides-Extra: dev
|
|
41
|
-
Requires-Dist: boto3-stubs[s3,swf]; extra == 'dev'
|
|
42
|
-
Requires-Dist: cffi==v1.17.0rc1; (python_full_version == '3.13.0b4') and extra == 'dev'
|
|
43
|
-
Requires-Dist: flaky; extra == 'dev'
|
|
44
|
-
Requires-Dist: hatch; extra == 'dev'
|
|
45
|
-
Requires-Dist: invoke; extra == 'dev'
|
|
46
|
-
Requires-Dist: moto<5.0.0,>=4.2.8; extra == 'dev'
|
|
47
|
-
Requires-Dist: packaging; extra == 'dev'
|
|
48
|
-
Requires-Dist: pre-commit; extra == 'dev'
|
|
49
|
-
Requires-Dist: pytest; extra == 'dev'
|
|
50
|
-
Requires-Dist: pytest-xdist>=3.2.0; extra == 'dev'
|
|
51
|
-
Requires-Dist: ruff; extra == 'dev'
|
|
52
|
-
Requires-Dist: setuptools<72; extra == 'dev'
|
|
53
|
-
Requires-Dist: sphinx; extra == 'dev'
|
|
54
|
-
Requires-Dist: sphinx-rtd-theme; extra == 'dev'
|
|
55
|
-
Requires-Dist: sure; extra == 'dev'
|
|
56
|
-
Requires-Dist: twine; extra == 'dev'
|
|
57
|
-
Requires-Dist: typing-extensions; extra == 'dev'
|
|
58
|
-
Requires-Dist: vcrpy; extra == 'dev'
|
|
59
|
-
Provides-Extra: doc
|
|
60
|
-
Requires-Dist: markdown-include; extra == 'doc'
|
|
61
|
-
Requires-Dist: mkdocs; extra == 'doc'
|
|
62
|
-
Requires-Dist: mkdocs-material; extra == 'doc'
|
|
63
|
-
Requires-Dist: pygments; extra == 'doc'
|
|
64
|
-
Requires-Dist: pymdown-extensions; extra == 'doc'
|
|
65
40
|
Description-Content-Type: text/markdown
|
|
66
41
|
|
|
67
42
|
Simpleflow
|
|
@@ -7,7 +7,7 @@ name = "simpleflow"
|
|
|
7
7
|
description = "Python library for dataflow programming with Amazon SWF"
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
requires-python = ">=3.7"
|
|
10
|
-
license =
|
|
10
|
+
license = "MIT"
|
|
11
11
|
authors = [
|
|
12
12
|
{ name = "Greg Leclercq" },
|
|
13
13
|
]
|
|
@@ -48,36 +48,6 @@ dependencies = [
|
|
|
48
48
|
"pytz",
|
|
49
49
|
]
|
|
50
50
|
|
|
51
|
-
[project.optional-dependencies]
|
|
52
|
-
dev = [
|
|
53
|
-
"boto3-stubs[s3,swf]",
|
|
54
|
-
"cffi==v1.17.0rc1; python_full_version=='3.13.0b4'", # via cryptography via moto, secretstorage
|
|
55
|
-
"flaky",
|
|
56
|
-
"hatch",
|
|
57
|
-
"invoke",
|
|
58
|
-
"moto>=4.2.8,<5.0.0",
|
|
59
|
-
"packaging",
|
|
60
|
-
"pre-commit",
|
|
61
|
-
"pytest",
|
|
62
|
-
"pytest-xdist>=3.2.0",
|
|
63
|
-
"ruff",
|
|
64
|
-
"setuptools<72", # See https://github.com/pypa/setuptools/issues/4519
|
|
65
|
-
"sphinx",
|
|
66
|
-
"sphinx_rtd_theme",
|
|
67
|
-
"sure",
|
|
68
|
-
"typing-extensions",
|
|
69
|
-
"vcrpy",
|
|
70
|
-
"twine",
|
|
71
|
-
]
|
|
72
|
-
|
|
73
|
-
doc = [
|
|
74
|
-
"mkdocs",
|
|
75
|
-
"mkdocs-material",
|
|
76
|
-
"pygments",
|
|
77
|
-
"pymdown-extensions",
|
|
78
|
-
"markdown-include",
|
|
79
|
-
]
|
|
80
|
-
|
|
81
51
|
[project.urls]
|
|
82
52
|
documentation = "https://botify-labs.github.io/simpleflow"
|
|
83
53
|
repository = "https://github.com/botify-labs/simpleflow"
|
|
@@ -97,10 +67,11 @@ extend-select = [
|
|
|
97
67
|
"W", # pycodestyle warnings
|
|
98
68
|
"RUF", # ruff
|
|
99
69
|
]
|
|
100
|
-
fixable = ["ALL"]
|
|
101
70
|
allowed-confusables = ["‘", "’"]
|
|
102
71
|
extend-ignore = [
|
|
103
72
|
]
|
|
73
|
+
ignore = ["E501"]
|
|
74
|
+
|
|
104
75
|
[tool.ruff.lint.isort]
|
|
105
76
|
required-imports = ["from __future__ import annotations"]
|
|
106
77
|
|
|
@@ -117,3 +88,43 @@ path = "simpleflow/__init__.py"
|
|
|
117
88
|
[tool.hatch.build]
|
|
118
89
|
include = ["/simpleflow"]
|
|
119
90
|
exclude = ["*~"]
|
|
91
|
+
|
|
92
|
+
[dependency-groups]
|
|
93
|
+
dev = [
|
|
94
|
+
"boto3-stubs[s3,swf]",
|
|
95
|
+
"cffi==v1.17.0rc1; python_full_version=='3.13.0b4'", # via cryptography via moto, secretstorage
|
|
96
|
+
"flaky",
|
|
97
|
+
"hatch",
|
|
98
|
+
"invoke",
|
|
99
|
+
"moto>=4.2.8,<5.0.0",
|
|
100
|
+
"packaging",
|
|
101
|
+
"pre-commit",
|
|
102
|
+
"pytest",
|
|
103
|
+
"pytest-xdist>=3.2.0",
|
|
104
|
+
"ruff",
|
|
105
|
+
"setuptools<72", # See https://github.com/pypa/setuptools/issues/4519
|
|
106
|
+
"sphinx",
|
|
107
|
+
"sphinx_rtd_theme",
|
|
108
|
+
"sure",
|
|
109
|
+
"typing-extensions",
|
|
110
|
+
"vcrpy",
|
|
111
|
+
"twine",
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
doc = [
|
|
115
|
+
"mkdocs",
|
|
116
|
+
"mkdocs-material",
|
|
117
|
+
"pygments",
|
|
118
|
+
"pymdown-extensions",
|
|
119
|
+
"markdown-include",
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
[[tool.uv.index]]
|
|
123
|
+
name = "pypi"
|
|
124
|
+
url = "https://pypi.org/simple/"
|
|
125
|
+
publish-url = "https://pypi.org/legacy/"
|
|
126
|
+
|
|
127
|
+
[[tool.uv.index]]
|
|
128
|
+
name = "testpypi"
|
|
129
|
+
url = "https://test.pypi.org/simple/"
|
|
130
|
+
publish-url = "https://test.pypi.org/legacy/"
|
|
@@ -9,6 +9,7 @@ import time
|
|
|
9
9
|
from contextlib import contextmanager
|
|
10
10
|
from datetime import datetime
|
|
11
11
|
from typing import TYPE_CHECKING
|
|
12
|
+
from urllib.parse import unquote
|
|
12
13
|
from uuid import uuid4
|
|
13
14
|
|
|
14
15
|
import click
|
|
@@ -50,6 +51,18 @@ def comma_separated_list(value: str) -> list[str]:
|
|
|
50
51
|
return value.split(",")
|
|
51
52
|
|
|
52
53
|
|
|
54
|
+
class RunIdParamType(click.ParamType):
|
|
55
|
+
name = "str"
|
|
56
|
+
|
|
57
|
+
def convert(self, value: Any, param: click.Parameter | None, ctx: click.Context | None) -> str:
|
|
58
|
+
if "%" not in value:
|
|
59
|
+
return value
|
|
60
|
+
return unquote(value)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
RUN_ID = RunIdParamType()
|
|
64
|
+
|
|
65
|
+
|
|
53
66
|
CONTEXT_SETTINGS = dict(help_option_names=["--help", "-h"])
|
|
54
67
|
|
|
55
68
|
|
|
@@ -207,7 +220,7 @@ def start_workflow(
|
|
|
207
220
|
return execution
|
|
208
221
|
|
|
209
222
|
|
|
210
|
-
@click.argument("run_id", required=False)
|
|
223
|
+
@click.argument("run_id", type=RUN_ID, required=False)
|
|
211
224
|
@click.argument("workflow_id")
|
|
212
225
|
@click.argument(
|
|
213
226
|
"domain",
|
|
@@ -223,10 +236,13 @@ def terminate_workflow(
|
|
|
223
236
|
run_id: str | None,
|
|
224
237
|
):
|
|
225
238
|
ex = helpers.get_workflow_execution(domain, workflow_id, run_id)
|
|
239
|
+
if not ex:
|
|
240
|
+
print(f"Execution {workflow_id} {run_id} not found" if run_id else f"Workflow {workflow_id} not found")
|
|
241
|
+
sys.exit(1)
|
|
226
242
|
ex.terminate()
|
|
227
243
|
|
|
228
244
|
|
|
229
|
-
@click.argument("run_id", required=False)
|
|
245
|
+
@click.argument("run_id", type=RUN_ID, required=False)
|
|
230
246
|
@click.argument("workflow_id")
|
|
231
247
|
@click.argument(
|
|
232
248
|
"domain",
|
|
@@ -238,6 +254,9 @@ def terminate_workflow(
|
|
|
238
254
|
)
|
|
239
255
|
def restart_workflow(domain: str, workflow_id: str, run_id: str | None):
|
|
240
256
|
ex = helpers.get_workflow_execution(domain, workflow_id, run_id)
|
|
257
|
+
if not ex:
|
|
258
|
+
print(f"Execution {workflow_id} {run_id} not found" if run_id else f"Workflow {workflow_id} not found")
|
|
259
|
+
sys.exit(1)
|
|
241
260
|
history = ex.history()
|
|
242
261
|
ex.terminate(reason="workflow.restart")
|
|
243
262
|
new_ex = ex.workflow_type.start_execution(
|
|
@@ -258,7 +277,7 @@ def with_format(ctx):
|
|
|
258
277
|
)
|
|
259
278
|
|
|
260
279
|
|
|
261
|
-
@click.argument("run_id", required=False)
|
|
280
|
+
@click.argument("run_id", type=RUN_ID, required=False)
|
|
262
281
|
@click.argument("workflow_id")
|
|
263
282
|
@click.argument(
|
|
264
283
|
"domain",
|
|
@@ -283,7 +302,7 @@ def workflow_info(ctx, domain: str, workflow_id: str, run_id: str | None):
|
|
|
283
302
|
type=int,
|
|
284
303
|
help="Maximum number of tasks to display.",
|
|
285
304
|
)
|
|
286
|
-
@click.argument("run_id", required=False)
|
|
305
|
+
@click.argument("run_id", type=RUN_ID, required=False)
|
|
287
306
|
@click.argument("workflow_id")
|
|
288
307
|
@click.argument(
|
|
289
308
|
"domain",
|
|
@@ -302,6 +321,7 @@ def profile(ctx, domain, workflow_id, run_id, nb_tasks):
|
|
|
302
321
|
)
|
|
303
322
|
|
|
304
323
|
|
|
324
|
+
# FIXME superseded by history
|
|
305
325
|
@click.option(
|
|
306
326
|
"--nb-tasks",
|
|
307
327
|
"-n",
|
|
@@ -309,7 +329,7 @@ def profile(ctx, domain, workflow_id, run_id, nb_tasks):
|
|
|
309
329
|
type=int,
|
|
310
330
|
help="Maximum number of tasks to display.",
|
|
311
331
|
)
|
|
312
|
-
@click.argument("run_id", required=False)
|
|
332
|
+
@click.argument("run_id", type=RUN_ID, required=False)
|
|
313
333
|
@click.argument("workflow_id")
|
|
314
334
|
@click.argument(
|
|
315
335
|
"domain",
|
|
@@ -334,6 +354,7 @@ def workflow_tasks(
|
|
|
334
354
|
)
|
|
335
355
|
|
|
336
356
|
|
|
357
|
+
# FIXME superseded by filter
|
|
337
358
|
@click.argument(
|
|
338
359
|
"domain",
|
|
339
360
|
envvar="SWF_DOMAIN",
|
|
@@ -360,18 +381,19 @@ def list_workflows(ctx, domain: str, status: str, started_since: int):
|
|
|
360
381
|
_NOTSET = object()
|
|
361
382
|
|
|
362
383
|
|
|
363
|
-
@click.argument(
|
|
364
|
-
"domain",
|
|
365
|
-
envvar="SWF_DOMAIN",
|
|
366
|
-
)
|
|
367
384
|
@cli.command(
|
|
368
385
|
"workflow.history",
|
|
369
386
|
help="Workflow history from workflow WORKFLOW_ID [RUN_ID].",
|
|
370
387
|
)
|
|
371
388
|
@click.argument("workflow_id")
|
|
372
|
-
@click.argument("run_id", required=False)
|
|
389
|
+
@click.argument("run_id", type=RUN_ID, required=False)
|
|
390
|
+
@click.option(
|
|
391
|
+
"--domain",
|
|
392
|
+
envvar="SWF_DOMAIN",
|
|
393
|
+
)
|
|
373
394
|
@click.option(
|
|
374
395
|
"--output-format",
|
|
396
|
+
"--of",
|
|
375
397
|
"-o",
|
|
376
398
|
required=False,
|
|
377
399
|
type=click.Choice(["events", "raw", "cooked"]),
|
|
@@ -388,12 +410,15 @@ def workflow_history(
|
|
|
388
410
|
output_format: str,
|
|
389
411
|
reverse_order: bool = False,
|
|
390
412
|
) -> None:
|
|
391
|
-
from simpleflow.swf.mapper.models.history.base import History as BaseHistory
|
|
392
|
-
|
|
393
413
|
if ctx.parent.params["format"] != "json" or not ctx.parent.params["header"]:
|
|
394
414
|
raise NotImplementedError("Only pretty JSON mode is implemented")
|
|
395
415
|
|
|
416
|
+
from simpleflow.swf.mapper.models.history.base import History as BaseHistory
|
|
417
|
+
|
|
396
418
|
ex = helpers.get_workflow_execution(domain, workflow_id, run_id)
|
|
419
|
+
if not ex:
|
|
420
|
+
print(f"Execution {workflow_id} {run_id} not found" if run_id else f"Workflow {workflow_id} not found")
|
|
421
|
+
sys.exit(1)
|
|
397
422
|
events = ex.history_events(
|
|
398
423
|
callback=get_progression_callback("events"),
|
|
399
424
|
reverse_order=reverse_order,
|
|
@@ -418,11 +443,15 @@ def workflow_history(
|
|
|
418
443
|
elif output_format == "cooked":
|
|
419
444
|
history.parse()
|
|
420
445
|
events = {
|
|
446
|
+
"workflow": history.workflow,
|
|
421
447
|
"activities": history.activities,
|
|
422
448
|
"child_workflows": history.child_workflows,
|
|
423
449
|
"markers": history.markers,
|
|
424
|
-
"signals": history.signals,
|
|
425
450
|
"timers": history.timers,
|
|
451
|
+
"signals": history.signals,
|
|
452
|
+
"signal_lists": history.signal_lists,
|
|
453
|
+
"external_workflows_signaling": history.external_workflows_signaling,
|
|
454
|
+
"signaled_workflows": history.signaled_workflows,
|
|
426
455
|
}
|
|
427
456
|
else:
|
|
428
457
|
raise NotImplementedError
|
|
@@ -740,7 +769,7 @@ def standalone(
|
|
|
740
769
|
# get the previous execution history, it will serve as "default history"
|
|
741
770
|
# for activities that succeeded in the previous execution
|
|
742
771
|
logger.info(
|
|
743
|
-
f"retrieving history of previous execution: domain={domain}
|
|
772
|
+
f"retrieving history of previous execution: domain={domain} workflow_id={repair} run_id={repair_run_id}"
|
|
744
773
|
)
|
|
745
774
|
workflow_execution = get_workflow_execution(domain, repair, run_id=repair_run_id)
|
|
746
775
|
previous_history = History(workflow_execution.history())
|
|
@@ -826,6 +855,11 @@ def standalone(
|
|
|
826
855
|
ex.workflow_id,
|
|
827
856
|
ex.run_id,
|
|
828
857
|
)
|
|
858
|
+
if not ex:
|
|
859
|
+
print(
|
|
860
|
+
f"Execution {workflow_id} {ex.run_id} not found" if ex.run_id else f"Workflow {workflow_id} not found"
|
|
861
|
+
)
|
|
862
|
+
sys.exit(1)
|
|
829
863
|
if display_status:
|
|
830
864
|
print(f"status: {ex.status}", file=sys.stderr)
|
|
831
865
|
if ex.status == ex.STATUS_CLOSED:
|
|
@@ -841,7 +875,7 @@ def standalone(
|
|
|
841
875
|
@click.option("--domain", envvar="SWF_DOMAIN", required=False, help="Amazon SWF Domain.")
|
|
842
876
|
@click.option("--workflow-id", required=True, help="ID of the workflow execution.")
|
|
843
877
|
@click.option("--input", "-i", required=False, help="JSON input of the workflow.")
|
|
844
|
-
@click.option("--run-id", required=False, help="Run ID of the workflow execution.")
|
|
878
|
+
@click.option("--run-id", type=RUN_ID, required=False, help="Run ID of the workflow execution.")
|
|
845
879
|
@click.option(
|
|
846
880
|
"--scheduled-id",
|
|
847
881
|
required=False,
|
|
@@ -891,7 +925,7 @@ def activity_rerun(domain, workflow_id, run_id, input, scheduled_id, activity_id
|
|
|
891
925
|
for line in json_dumps(params, pretty=True).split("\n"):
|
|
892
926
|
logger.debug(line)
|
|
893
927
|
if input_override:
|
|
894
|
-
logger.info("NB: input will be
|
|
928
|
+
logger.info("NB: input will be overridden with the passed one!")
|
|
895
929
|
logger.info(f"Will re-run: {task}(*{args}, **{kwargs}) [+meta={meta}]")
|
|
896
930
|
|
|
897
931
|
# download binaries if needed
|
|
@@ -913,8 +947,7 @@ def activity_rerun(domain, workflow_id, run_id, input, scheduled_id, activity_id
|
|
|
913
947
|
)
|
|
914
948
|
@cli.command(
|
|
915
949
|
"info",
|
|
916
|
-
help="Display versions, settings, and environment variables. "
|
|
917
|
-
"Available sections: versions, settings, environment.",
|
|
950
|
+
help="Display versions, settings, and environment variables. Available sections: versions, settings, environment.",
|
|
918
951
|
)
|
|
919
952
|
def info(sections):
|
|
920
953
|
@contextmanager
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from simpleflow.activity import Activity
|
|
4
|
-
from simpleflow.utils import import_object_from_module
|
|
4
|
+
from simpleflow.utils import format_exc, import_object_from_module
|
|
5
5
|
|
|
6
6
|
from .exceptions import DispatchError
|
|
7
7
|
|
|
@@ -25,9 +25,9 @@ class Dispatcher:
|
|
|
25
25
|
module_name, activity_name = name.rsplit(".", 1)
|
|
26
26
|
try:
|
|
27
27
|
activity = import_object_from_module(module_name, activity_name)
|
|
28
|
-
except ImportError:
|
|
28
|
+
except ImportError as e:
|
|
29
29
|
# We were not able to import a function at all.
|
|
30
|
-
raise DispatchError(f"unable to import '{name}'")
|
|
30
|
+
raise DispatchError(f"unable to import '{name}': {format_exc(e)}")
|
|
31
31
|
if not isinstance(activity, Activity):
|
|
32
32
|
# We managed to import a function (or callable) but it's not an
|
|
33
33
|
# "Activity". We will transform it into an Activity now. That way
|
|
@@ -43,11 +43,16 @@ class History:
|
|
|
43
43
|
self.started_decision_id: int | None = None
|
|
44
44
|
self.completed_decision_id: int | None = None
|
|
45
45
|
self.last_event_id: int | None = None
|
|
46
|
+
self._workflow: dict[str, Any] = {}
|
|
46
47
|
|
|
47
48
|
@property
|
|
48
49
|
def swf_history(self) -> simpleflow.swf.mapper.models.history.History:
|
|
49
50
|
return self._history
|
|
50
51
|
|
|
52
|
+
@property
|
|
53
|
+
def workflow(self):
|
|
54
|
+
return self._workflow
|
|
55
|
+
|
|
51
56
|
@property
|
|
52
57
|
def activities(self) -> dict[str, ActivityTaskEventDict]:
|
|
53
58
|
"""
|
|
@@ -432,6 +437,118 @@ class History:
|
|
|
432
437
|
"""
|
|
433
438
|
Parse a workflow event.
|
|
434
439
|
"""
|
|
440
|
+
if event.state == "started":
|
|
441
|
+
self._workflow.update(
|
|
442
|
+
{
|
|
443
|
+
"state": event.state,
|
|
444
|
+
f"{event.state}_id": event.id,
|
|
445
|
+
f"{event.state}_timestamp": event.timestamp,
|
|
446
|
+
"child_policy": getattr(event, "child_policy", None),
|
|
447
|
+
"task_list": event.task_list["name"],
|
|
448
|
+
"workflow_type": event.workflow_type,
|
|
449
|
+
"continued_execution_run_id": getattr(event, "continued_execution_run_id", None),
|
|
450
|
+
"execution_start_to_close_timeout": getattr(event, "execution_start_to_close_timeout", None),
|
|
451
|
+
"input": getattr(event, "input", None),
|
|
452
|
+
"lambda_role": getattr(event, "lambda_role", None),
|
|
453
|
+
"parent_initiated_event_id": getattr(event, "parent_initiated_event_id", None),
|
|
454
|
+
"parent_workflow_execution": getattr(event, "parent_workflow_execution", None),
|
|
455
|
+
"tag_list": getattr(event, "tag_list", None),
|
|
456
|
+
"task_priority": getattr(event, "task_priority", None),
|
|
457
|
+
"task_start_to_close_timeout": getattr(event, "task_start_to_close_timeout", None),
|
|
458
|
+
}
|
|
459
|
+
)
|
|
460
|
+
elif event.state == "continued_as_new":
|
|
461
|
+
self._workflow.update(
|
|
462
|
+
{
|
|
463
|
+
"state": event.state,
|
|
464
|
+
f"{event.state}_id": event.id,
|
|
465
|
+
f"{event.state}_timestamp": event.timestamp,
|
|
466
|
+
f"{event.state}_decision_task_completed_event_id": event.decision_task_completed_event_id,
|
|
467
|
+
"new_execution_run_id": event.new_execution_run_id,
|
|
468
|
+
"task_list": event.task_list["name"],
|
|
469
|
+
"workflow_type": event.workflow_type,
|
|
470
|
+
"execution_start_to_close_timeout": getattr(event, "execution_start_to_close_timeout", None),
|
|
471
|
+
"input": getattr(event, "input", None),
|
|
472
|
+
"lambda_role": getattr(event, "lambda_role", None),
|
|
473
|
+
"tag_list": getattr(event, "tag_list", None),
|
|
474
|
+
"task_priority": getattr(event, "task_priority", None),
|
|
475
|
+
"task_start_to_close_timeout": getattr(event, "task_start_to_close_timeout", None),
|
|
476
|
+
}
|
|
477
|
+
)
|
|
478
|
+
elif event.state == "completed":
|
|
479
|
+
self._workflow.update(
|
|
480
|
+
{
|
|
481
|
+
"state": event.state,
|
|
482
|
+
f"{event.state}_id": event.id,
|
|
483
|
+
f"{event.state}_timestamp": event.timestamp,
|
|
484
|
+
"initiated_event_id": getattr(event, "initiated_event_id", None),
|
|
485
|
+
"result": getattr(event, "result", None),
|
|
486
|
+
}
|
|
487
|
+
)
|
|
488
|
+
elif event.state == "cancelled":
|
|
489
|
+
self._workflow.update(
|
|
490
|
+
{
|
|
491
|
+
"state": event.state,
|
|
492
|
+
f"{event.state}_id": event.id,
|
|
493
|
+
f"{event.state}_timestamp": event.timestamp,
|
|
494
|
+
"initiated_event_id": getattr(event, "initiated_event_id", None),
|
|
495
|
+
"decision_task_completed_event_id": event.decision_task_completed_event_id,
|
|
496
|
+
"details": getattr(event, "details", None),
|
|
497
|
+
}
|
|
498
|
+
)
|
|
499
|
+
elif event.state == "failed":
|
|
500
|
+
self._workflow.update(
|
|
501
|
+
{
|
|
502
|
+
"state": event.state,
|
|
503
|
+
f"{event.state}_id": event.id,
|
|
504
|
+
f"{event.state}_timestamp": event.timestamp,
|
|
505
|
+
"initiated_event_id": getattr(event, "initiated_event_id", None),
|
|
506
|
+
"decision_task_completed_event_id": event.decision_task_completed_event_id,
|
|
507
|
+
"reason": getattr(event, "reason", None),
|
|
508
|
+
"details": getattr(event, "details", None),
|
|
509
|
+
}
|
|
510
|
+
)
|
|
511
|
+
elif event.state == "terminated":
|
|
512
|
+
self._workflow.update(
|
|
513
|
+
{
|
|
514
|
+
"state": event.state,
|
|
515
|
+
f"{event.state}_id": event.id,
|
|
516
|
+
f"{event.state}_timestamp": event.timestamp,
|
|
517
|
+
"initiated_event_id": getattr(event, "initiated_event_id", None),
|
|
518
|
+
"cause": getattr(event, "cause", None),
|
|
519
|
+
"details": getattr(event, "details", None),
|
|
520
|
+
}
|
|
521
|
+
)
|
|
522
|
+
elif event.state == "timed_out":
|
|
523
|
+
self._workflow.update(
|
|
524
|
+
{
|
|
525
|
+
"state": event.state,
|
|
526
|
+
f"{event.state}_id": event.id,
|
|
527
|
+
f"{event.state}_timestamp": event.timestamp,
|
|
528
|
+
"initiated_event_id": getattr(event, "initiated_event_id", None),
|
|
529
|
+
"timeout_type": event.timeout_type,
|
|
530
|
+
}
|
|
531
|
+
)
|
|
532
|
+
# elif event.state in (
|
|
533
|
+
# "cancel_failed",
|
|
534
|
+
# "complete_failed",
|
|
535
|
+
# "continue_as_new",
|
|
536
|
+
# "fail_failed",
|
|
537
|
+
# "start_child_failed",
|
|
538
|
+
# "start_failed",
|
|
539
|
+
# "terminate_failed",
|
|
540
|
+
# ):
|
|
541
|
+
# self._workflow.update(
|
|
542
|
+
# {
|
|
543
|
+
# "state": event.state,
|
|
544
|
+
# f"{event.state}_id": event.id,
|
|
545
|
+
# f"{event.state}_cause": getattr(event, "cause", None),
|
|
546
|
+
# f"{event.state}_decision_task_completed_event_id": event.decision_task_completed_event_id,
|
|
547
|
+
# }
|
|
548
|
+
# )
|
|
549
|
+
|
|
550
|
+
if event.state == "cancel_requested":
|
|
551
|
+
self._workflow.update()
|
|
435
552
|
if event.state == "signaled":
|
|
436
553
|
signal = {
|
|
437
554
|
"type": "signal",
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import collections
|
|
4
3
|
import sys
|
|
5
4
|
import traceback
|
|
6
5
|
import uuid
|
|
@@ -27,8 +26,8 @@ class Executor(executor.Executor):
|
|
|
27
26
|
super().__init__(workflow_class)
|
|
28
27
|
self.update_workflow_class()
|
|
29
28
|
self.nb_activities = 0
|
|
30
|
-
self.signals_sent = set()
|
|
31
|
-
self._markers =
|
|
29
|
+
self.signals_sent: set[str] = set()
|
|
30
|
+
self._markers: dict[str, list[Marker]] = {}
|
|
32
31
|
|
|
33
32
|
self.wf_run_id = []
|
|
34
33
|
self.wf_id = []
|
|
@@ -206,7 +205,7 @@ class Executor(executor.Executor):
|
|
|
206
205
|
self.update_workflow_class()
|
|
207
206
|
self.nb_activities = 0
|
|
208
207
|
self.signals_sent = set()
|
|
209
|
-
self._markers =
|
|
208
|
+
self._markers = {}
|
|
210
209
|
|
|
211
210
|
self.wf_run_id = []
|
|
212
211
|
self.wf_id = []
|
|
@@ -6,7 +6,6 @@ import os
|
|
|
6
6
|
import re
|
|
7
7
|
import time
|
|
8
8
|
from abc import ABC
|
|
9
|
-
from collections import OrderedDict
|
|
10
9
|
from typing import Any
|
|
11
10
|
from urllib.parse import quote_plus
|
|
12
11
|
|
|
@@ -18,31 +17,29 @@ ACTIVITY_KEY_RE = re.compile(r"activity\.(.+)\.json")
|
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
class StepIO:
|
|
21
|
-
def __init__(self):
|
|
20
|
+
def __init__(self) -> None:
|
|
22
21
|
self.bytes = 0
|
|
23
22
|
self.records = 0
|
|
24
23
|
self.sampled = False
|
|
25
24
|
|
|
26
|
-
def get_stats(self, time_total):
|
|
25
|
+
def get_stats(self, time_total: float) -> dict[str, Any]:
|
|
27
26
|
mb_s = None
|
|
28
27
|
rec_s = None
|
|
29
28
|
if self.bytes:
|
|
30
29
|
mb_s = round(float(self.bytes) / (1024 * 1024) / time_total, 2)
|
|
31
30
|
if self.records:
|
|
32
31
|
rec_s = int(self.records / time_total)
|
|
33
|
-
return
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
]
|
|
41
|
-
)
|
|
32
|
+
return {
|
|
33
|
+
"bytes": self.bytes,
|
|
34
|
+
"records": self.records,
|
|
35
|
+
"mb_s": mb_s,
|
|
36
|
+
"rec_s": rec_s,
|
|
37
|
+
"sampled": self.sampled,
|
|
38
|
+
}
|
|
42
39
|
|
|
43
40
|
|
|
44
41
|
class Step:
|
|
45
|
-
def __init__(self, name, task):
|
|
42
|
+
def __init__(self, name: str, task: MetrologyTask) -> None:
|
|
46
43
|
self.name = name
|
|
47
44
|
self.task = task
|
|
48
45
|
self.read = StepIO()
|
|
@@ -57,22 +54,17 @@ class Step:
|
|
|
57
54
|
self.time_total = self.time_finished - self.time_started
|
|
58
55
|
|
|
59
56
|
def get_stats(self):
|
|
60
|
-
stats =
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
]
|
|
70
|
-
)
|
|
71
|
-
return stats
|
|
57
|
+
stats = {
|
|
58
|
+
"name": self.name,
|
|
59
|
+
"metadata": self.metadata,
|
|
60
|
+
"time_started": self.time_started,
|
|
61
|
+
"time_finished": self.time_finished,
|
|
62
|
+
"time_total": self.time_total,
|
|
63
|
+
"read": self.read.get_stats(self.time_total),
|
|
64
|
+
"write": self.write.get_stats(self.time_total),
|
|
65
|
+
}
|
|
72
66
|
|
|
73
|
-
|
|
74
|
-
for k, v in kvs:
|
|
75
|
-
self.metadata[k] = v
|
|
67
|
+
return stats
|
|
76
68
|
|
|
77
69
|
|
|
78
70
|
class StepExecution:
|
|
@@ -90,14 +82,14 @@ class MetrologyTask:
|
|
|
90
82
|
context: dict[str, Any]
|
|
91
83
|
steps: list[Step]
|
|
92
84
|
|
|
93
|
-
def can_upload(self):
|
|
85
|
+
def can_upload(self) -> bool:
|
|
94
86
|
if not hasattr(self, "context"):
|
|
95
87
|
return False
|
|
96
88
|
return all(c in self.context for c in ("workflow_id", "run_id", "activity_id"))
|
|
97
89
|
|
|
98
90
|
@property
|
|
99
91
|
def metrology_path(self):
|
|
100
|
-
path = []
|
|
92
|
+
path: list[str] = []
|
|
101
93
|
if settings.METROLOGY_PATH_PREFIX is not None:
|
|
102
94
|
path.append(settings.METROLOGY_PATH_PREFIX)
|
|
103
95
|
path.append(self.context["workflow_id"])
|
|
@@ -105,7 +97,7 @@ class MetrologyTask:
|
|
|
105
97
|
path.append(f"activity.{self.context['activity_id']}.json")
|
|
106
98
|
return str(os.path.join(*path))
|
|
107
99
|
|
|
108
|
-
def step(self, name):
|
|
100
|
+
def step(self, name: str) -> StepExecution:
|
|
109
101
|
"""
|
|
110
102
|
To be called in a `with` execution
|
|
111
103
|
Ex :
|
|
@@ -208,7 +208,7 @@ class Supervisor(NamedMixin):
|
|
|
208
208
|
Terminate all worker processes managed by this Supervisor.
|
|
209
209
|
"""
|
|
210
210
|
self._terminating = True
|
|
211
|
-
logger.info("process: will stop workers, this might take up several minutes.
|
|
211
|
+
logger.info("process: will stop workers, this might take up several minutes. Please, be patient.")
|
|
212
212
|
self._killall()
|
|
213
213
|
|
|
214
214
|
def _killall(self):
|