scalable-pypeline 2.1.9__py2.py3-none-any.whl → 2.1.10__py2.py3-none-any.whl
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.
- pypeline/__init__.py +1 -1
- pypeline/dramatiq.py +43 -37
- pypeline/pipeline_config_schema.py +17 -0
- pypeline/pipelines/composition/pypeline_composition.py +4 -1
- pypeline/pipelines/factory.py +2 -1
- pypeline/pipelines/middleware/pypeline_middleware.py +13 -5
- pypeline/utils/dramatiq_utils.py +6 -2
- {scalable_pypeline-2.1.9.dist-info → scalable_pypeline-2.1.10.dist-info}/METADATA +1 -1
- {scalable_pypeline-2.1.9.dist-info → scalable_pypeline-2.1.10.dist-info}/RECORD +13 -13
- {scalable_pypeline-2.1.9.dist-info → scalable_pypeline-2.1.10.dist-info}/LICENSE +0 -0
- {scalable_pypeline-2.1.9.dist-info → scalable_pypeline-2.1.10.dist-info}/WHEEL +0 -0
- {scalable_pypeline-2.1.9.dist-info → scalable_pypeline-2.1.10.dist-info}/entry_points.txt +0 -0
- {scalable_pypeline-2.1.9.dist-info → scalable_pypeline-2.1.10.dist-info}/top_level.txt +0 -0
pypeline/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "2.1.
|
1
|
+
__version__ = "2.1.10"
|
pypeline/dramatiq.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import copy
|
1
2
|
import typing
|
2
3
|
import pika
|
3
4
|
import logging
|
@@ -101,45 +102,50 @@ def register_actors_for_workers(broker: Broker):
|
|
101
102
|
|
102
103
|
if not service:
|
103
104
|
return
|
104
|
-
|
105
|
-
|
106
|
-
for
|
107
|
-
|
105
|
+
|
106
|
+
worker_registered_tasks = [
|
107
|
+
task_handler["handler"] for task_handler in service.get("registeredTasks")
|
108
|
+
]
|
109
|
+
|
110
|
+
# Loop over the pipelines to get metadata and other information about the task for registration
|
111
|
+
for pipeline_key, pipeline in pypeline_config["pipelines"].items():
|
112
|
+
for task, task_handler_meta in pipeline["config"]["taskDefinitions"].items():
|
108
113
|
if pipeline["schemaVersion"] == 1:
|
109
|
-
|
110
|
-
|
111
|
-
]
|
114
|
+
# Check if any task in this pipeline is registered
|
115
|
+
task_handlers = [task_handler_meta["handler"]]
|
112
116
|
elif pipeline["schemaVersion"] == 2:
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
117
|
+
task_handlers = [t for t in task_handler_meta["handlers"]]
|
118
|
+
|
119
|
+
for task_handler in task_handlers:
|
120
|
+
if task_handler in worker_registered_tasks:
|
121
|
+
server_type = task_handler_meta.get("serverType", None)
|
122
|
+
|
123
|
+
try:
|
124
|
+
pipeline_metadata = copy.deepcopy(
|
125
|
+
pipeline["config"]["metadata"]
|
126
|
+
)
|
127
|
+
tmp_handler = get_callable(task_handler)
|
128
|
+
if pipeline_metadata.get("maxRetry", 0) >= 0:
|
129
|
+
pipeline_metadata["store_results"] = True
|
130
|
+
_ = register_lazy_actor(
|
131
|
+
broker, tmp_handler, pipeline_metadata, server_type
|
132
|
+
)
|
133
|
+
except Exception as e:
|
134
|
+
logger.exception(
|
135
|
+
f"Unable to add a task {task_handler} to dramatiq: {e}"
|
136
|
+
)
|
137
|
+
# Loop over the scheduled jobs and create metadata and other information about the task for registration
|
138
|
+
for job in scheduled_jobs_config:
|
139
|
+
config = job["config"]
|
140
|
+
if config["task"] in worker_registered_tasks:
|
141
|
+
pipeline_meta = {"queue": config.get("queue", "default")}
|
142
|
+
try:
|
143
|
+
tmp_handler = get_callable(config["task"])
|
144
|
+
if pipeline_meta and pipeline_meta.get("maxRetry", 0) >= 0:
|
145
|
+
pipeline_meta["store_results"] = True
|
146
|
+
_ = register_lazy_actor(broker, tmp_handler, pipeline_meta, None)
|
147
|
+
except Exception as e:
|
148
|
+
logger.exception(f"Unable to add a task to dramatiq: {e}")
|
143
149
|
|
144
150
|
|
145
151
|
class Dramatiq:
|
@@ -4,6 +4,7 @@
|
|
4
4
|
import yaml
|
5
5
|
from marshmallow import Schema, fields, EXCLUDE, validates_schema
|
6
6
|
from marshmallow.exceptions import ValidationError
|
7
|
+
from marshmallow.validate import OneOf
|
7
8
|
|
8
9
|
from pypeline.pipeline_settings_schema import PipelineSettingsSchema
|
9
10
|
|
@@ -116,6 +117,14 @@ class TaskDefinitionsSchemaV1(ExcludeUnknownSchema):
|
|
116
117
|
example="custom-queue-name",
|
117
118
|
)
|
118
119
|
|
120
|
+
serverType = fields.String(
|
121
|
+
required=False,
|
122
|
+
validate=OneOf(
|
123
|
+
["xs", "s", "m", "l", "xl", "xxl", "xxxl"],
|
124
|
+
error="Invalid serverType. Available options: 'xs', 's', 'm', 'l', 'xl', 'xxl', 'xxxl'.",
|
125
|
+
),
|
126
|
+
)
|
127
|
+
|
119
128
|
|
120
129
|
class TaskDefinitionsSchemaV2(ExcludeUnknownSchema):
|
121
130
|
"""Schema for a single task's configuration"""
|
@@ -140,6 +149,14 @@ class TaskDefinitionsSchemaV2(ExcludeUnknownSchema):
|
|
140
149
|
example="custom-queue-name",
|
141
150
|
)
|
142
151
|
|
152
|
+
serverType = fields.String(
|
153
|
+
required=False,
|
154
|
+
validate=OneOf(
|
155
|
+
["xs", "s", "m", "l", "xl", "xxl", "xxxl"],
|
156
|
+
error="Invalid serverType. Available options: 'xs', 's', 'm', 'l', 'xl', 'xxl', 'xxxl'.",
|
157
|
+
),
|
158
|
+
)
|
159
|
+
|
143
160
|
|
144
161
|
class PipelineConfigSchemaBase(Schema):
|
145
162
|
"""Overall pipeline configuration schema"""
|
@@ -19,7 +19,6 @@ class Pypeline:
|
|
19
19
|
pipeline: dict,
|
20
20
|
scenarios: dict = {},
|
21
21
|
broker=None,
|
22
|
-
execution_id=None,
|
23
22
|
):
|
24
23
|
# Construct initial properties
|
25
24
|
self.pipeline = pipeline
|
@@ -78,10 +77,12 @@ class Pypeline:
|
|
78
77
|
handler = task_definitions[first_task]["handlers"][
|
79
78
|
scenario["taskReplacements"].get(first_task, 0)
|
80
79
|
]
|
80
|
+
server_type = task_definitions[first_task].get("serverType", None)
|
81
81
|
lazy_actor = register_lazy_actor(
|
82
82
|
self.broker,
|
83
83
|
get_callable(handler),
|
84
84
|
pipeline_config["metadata"],
|
85
|
+
server_type,
|
85
86
|
)
|
86
87
|
message = lazy_actor.message()
|
87
88
|
message.options["pipeline"] = pipeline
|
@@ -111,10 +112,12 @@ class Pypeline:
|
|
111
112
|
handler = task_definitions[first_task]["handlers"][
|
112
113
|
first_scenario_task_replacements.get(first_task, 0)
|
113
114
|
]
|
115
|
+
server_type = task_definitions[first_task].get("serverType", None)
|
114
116
|
lazy_actor = register_lazy_actor(
|
115
117
|
self.broker,
|
116
118
|
get_callable(handler),
|
117
119
|
pipeline_config["metadata"],
|
120
|
+
server_type,
|
118
121
|
)
|
119
122
|
message = lazy_actor.message()
|
120
123
|
message.options["pipeline"] = pipeline
|
pypeline/pipelines/factory.py
CHANGED
@@ -63,9 +63,10 @@ def dag_generator(
|
|
63
63
|
message_group = []
|
64
64
|
for task in task_group:
|
65
65
|
module_path = task_definitions[task]["handler"]
|
66
|
+
server_type = task_definitions[task].get("serverType", None)
|
66
67
|
tmp_handler = get_callable(module_path)
|
67
68
|
lazy_actor = register_lazy_actor(
|
68
|
-
broker, tmp_handler, pipeline_config["metadata"]
|
69
|
+
broker, tmp_handler, pipeline_config["metadata"], server_type
|
69
70
|
)
|
70
71
|
registered_actors[task] = lazy_actor
|
71
72
|
if args and not kwargs:
|
@@ -31,16 +31,14 @@ class PypelineMiddleware(Middleware):
|
|
31
31
|
task_name = message.options["task_name"]
|
32
32
|
task_key = f"{execution_id}-{task_name}"
|
33
33
|
|
34
|
-
# Signal to other jobs that current
|
34
|
+
# Signal to other jobs that current task is finished
|
35
35
|
locking_parallel_barrier = LockingParallelBarrier(
|
36
36
|
self.redis_url,
|
37
37
|
task_key=task_key,
|
38
38
|
lock_key=f"{message.options['base_case_execution_id']}-lock",
|
39
39
|
)
|
40
40
|
try:
|
41
|
-
locking_parallel_barrier.acquire_lock(
|
42
|
-
timeout=PARALLEL_PIPELINE_CALLBACK_BARRIER_TTL
|
43
|
-
)
|
41
|
+
locking_parallel_barrier.acquire_lock(timeout=10)
|
44
42
|
_ = locking_parallel_barrier.decrement_task_count()
|
45
43
|
finally:
|
46
44
|
locking_parallel_barrier.release_lock()
|
@@ -74,6 +72,9 @@ class PypelineMiddleware(Middleware):
|
|
74
72
|
finally:
|
75
73
|
locking_parallel_barrier.release_lock()
|
76
74
|
|
75
|
+
# If the lock didn't exist for the current tasks execution id then it would indicate
|
76
|
+
# that this is the start of a new scenario. Therefore we need to find the ancestor
|
77
|
+
# that is executed in the base case execution id and make sure it has completed
|
77
78
|
if not remaining_tasks:
|
78
79
|
task_key = f"{message.options['base_case_execution_id']}-{ancestor}"
|
79
80
|
|
@@ -95,7 +96,7 @@ class PypelineMiddleware(Middleware):
|
|
95
96
|
)
|
96
97
|
finally:
|
97
98
|
locking_parallel_barrier.release_lock()
|
98
|
-
if remaining_tasks >= 1:
|
99
|
+
if remaining_tasks is None or remaining_tasks >= 1:
|
99
100
|
ancestor_tasks_complete = False
|
100
101
|
break
|
101
102
|
|
@@ -103,6 +104,7 @@ class PypelineMiddleware(Middleware):
|
|
103
104
|
if not ancestor_tasks_complete:
|
104
105
|
break
|
105
106
|
|
107
|
+
# Handle situation where base case kicks off new scenario
|
106
108
|
if (
|
107
109
|
message.options["base_case_execution_id"]
|
108
110
|
== message.options["execution_id"]
|
@@ -124,11 +126,13 @@ class PypelineMiddleware(Middleware):
|
|
124
126
|
handler = task_definitions[child]["handlers"][
|
125
127
|
task_replacements.get(child, 0)
|
126
128
|
]
|
129
|
+
server_type = task_definitions[child].get("serverType", None)
|
127
130
|
|
128
131
|
lazy_actor = register_lazy_actor(
|
129
132
|
broker,
|
130
133
|
get_callable(handler),
|
131
134
|
pipeline_config["metadata"],
|
135
|
+
server_type,
|
132
136
|
)
|
133
137
|
scenario_message = lazy_actor.message()
|
134
138
|
scenario_message.options["pipeline"] = pipeline
|
@@ -154,6 +158,8 @@ class PypelineMiddleware(Middleware):
|
|
154
158
|
scenario["execution_id"]
|
155
159
|
)
|
156
160
|
messages.append(scenario_message)
|
161
|
+
|
162
|
+
# Kick off child task for current scenario
|
157
163
|
task_key = f"{execution_id}-{child}"
|
158
164
|
locking_parallel_barrier = LockingParallelBarrier(
|
159
165
|
self.redis_url,
|
@@ -164,10 +170,12 @@ class PypelineMiddleware(Middleware):
|
|
164
170
|
handler = task_definitions[child]["handlers"][
|
165
171
|
task_replacements.get(child, 0)
|
166
172
|
]
|
173
|
+
server_type = task_definitions[child].get("serverType", None)
|
167
174
|
lazy_actor = register_lazy_actor(
|
168
175
|
broker,
|
169
176
|
get_callable(handler),
|
170
177
|
pipeline_config["metadata"],
|
178
|
+
server_type,
|
171
179
|
)
|
172
180
|
|
173
181
|
child_message = lazy_actor.message()
|
pypeline/utils/dramatiq_utils.py
CHANGED
@@ -45,9 +45,13 @@ def register_lazy_actor(
|
|
45
45
|
broker: Broker,
|
46
46
|
fn: Optional[Callable[P, Union[Awaitable[R], R]]] = None,
|
47
47
|
pipeline_meta: typing.Dict = {},
|
48
|
+
server_type: Optional[str] = None,
|
48
49
|
**kwargs,
|
49
50
|
) -> typing.Type["LazyActor"]:
|
50
|
-
|
51
|
+
if server_type:
|
52
|
+
kwargs["queue_name"] = server_type + "-" + pipeline_meta.get("queue", "default")
|
53
|
+
else:
|
54
|
+
kwargs["queue_name"] = pipeline_meta.get("queue", "default")
|
51
55
|
kwargs["max_retries"] = pipeline_meta.get("maxRetry", DEFAULT_TASK_MAX_RETRY)
|
52
56
|
# Convert from seconds to milliseconds
|
53
57
|
kwargs["min_backoff"] = (
|
@@ -110,7 +114,7 @@ class LazyActor(object):
|
|
110
114
|
|
111
115
|
def register(self, broker):
|
112
116
|
self.actor = register_actor(
|
113
|
-
actor_name=f"{self.fn.__module__}.{self.fn.__name__}",
|
117
|
+
actor_name=f"{self.fn.__module__}.{self.fn.__name__}-{self.kw['queue_name']}",
|
114
118
|
broker=broker,
|
115
119
|
**self.kw,
|
116
120
|
)(ensure_return_value(default_value=True)(self.fn))
|
@@ -1,9 +1,9 @@
|
|
1
|
-
pypeline/__init__.py,sha256=
|
1
|
+
pypeline/__init__.py,sha256=zBzBCTHx_lpM20-2wHeccRHskIUls_oSQ1tzAOiGGrU,23
|
2
2
|
pypeline/barrier.py,sha256=oO964l9qOCOibweOHyNivmAvufdXOke9nz2tdgclouo,1172
|
3
3
|
pypeline/constants.py,sha256=EGSuLq4KhZ4bxrbtnUgKclELRyya5ipvv0WeybCzNAs,3049
|
4
|
-
pypeline/dramatiq.py,sha256=
|
4
|
+
pypeline/dramatiq.py,sha256=nnNxm2akL6hjqfjwQglK76LspZrdrL_2E_rDN5ThwZ8,13432
|
5
5
|
pypeline/extensions.py,sha256=BzOTnXhNxap3N7uIUUh_hO6dDwx08Vc_RJDE93_K0Lo,610
|
6
|
-
pypeline/pipeline_config_schema.py,sha256=
|
6
|
+
pypeline/pipeline_config_schema.py,sha256=ApgDqgINFDcmErVP7jJUJgkaVfwNRanj4q12ehWVJUU,11143
|
7
7
|
pypeline/pipeline_settings_schema.py,sha256=IBBtWqxrRA0MrUwNZEnGhYJbmag-sus1Ln6VCrUvuyY,20313
|
8
8
|
pypeline/pypeline_yaml.py,sha256=Og08sUKwOjq7JYPnkg-NIcGbHravYCkC5Arz22rZEtA,16981
|
9
9
|
pypeline/schedule_config_schema.py,sha256=vtZV-5wpGcAiYcXxdBPRkrjsbR6x_9E-1PC2elrKKbE,3611
|
@@ -14,24 +14,24 @@ pypeline/flask/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
|
|
14
14
|
pypeline/flask/api/pipelines.py,sha256=lw1ggsjp_Iha5MhyQGHtVW0akpVJnxIk0hn6NkC3c8s,9314
|
15
15
|
pypeline/flask/api/schedules.py,sha256=8PKCMdPucaer8opchNlI5aDssK2UqT79hHpeg5BMtTA,1210
|
16
16
|
pypeline/pipelines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
|
-
pypeline/pipelines/factory.py,sha256=
|
17
|
+
pypeline/pipelines/factory.py,sha256=p2b1XhhMYt_f5h2FAr6Zze1FfWz8SCyO9DEIS_EDDKE,3258
|
18
18
|
pypeline/pipelines/composition/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
19
|
pypeline/pipelines/composition/parallel_pipeline_composition.py,sha256=pTw9Xb9h4JnV4siFc3JStm5lB-i9djUADo3Kh5K3s7g,12976
|
20
|
-
pypeline/pipelines/composition/pypeline_composition.py,sha256=
|
20
|
+
pypeline/pipelines/composition/pypeline_composition.py,sha256=G6hptAN3LaVGm6DE7yhjGs-LDbw7m94-z08pLZCqNXA,8154
|
21
21
|
pypeline/pipelines/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
22
|
pypeline/pipelines/middleware/get_active_worker_id_middleware.py,sha256=X4ZfRk3L8MD00DTsGHth7oOdy-W7LQV96T8vu5UC42A,755
|
23
23
|
pypeline/pipelines/middleware/parallel_pipeline_middleware.py,sha256=kTp6niYoe2nXIiN6EGRfdpxrJyioo0GPxDkfefbGlEk,2821
|
24
|
-
pypeline/pipelines/middleware/pypeline_middleware.py,sha256=
|
24
|
+
pypeline/pipelines/middleware/pypeline_middleware.py,sha256=X3nQDiQQGs-rRyD8_-6SFMpM6-GGR2Qn0A6qlxmX3Qs,8756
|
25
25
|
pypeline/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
26
26
|
pypeline/utils/config_utils.py,sha256=rAIATyoW7kGETZ_Z2DqiXtGd7bJp5uPfcLtfNPOYsNs,2167
|
27
|
-
pypeline/utils/dramatiq_utils.py,sha256=
|
27
|
+
pypeline/utils/dramatiq_utils.py,sha256=DUdgVywm1182A4i69XzH9EIh1EJ9zAHmJLtOaVSW7pw,3844
|
28
28
|
pypeline/utils/module_utils.py,sha256=-yEJIukDCoXnmlZVXB6Dww25tH6GdPE5SoFqv6pfdVU,3682
|
29
29
|
pypeline/utils/pipeline_utils.py,sha256=kGP1QwCJikGC5QNRtzRXCDVewyRMpWIqERTNnxGLlSY,4795
|
30
30
|
pypeline/utils/schema_utils.py,sha256=Fgl0y9Cuo_TZeEx_S3gaSVnLjn6467LTkjb2ek7Ms98,851
|
31
31
|
tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
32
|
-
scalable_pypeline-2.1.
|
33
|
-
scalable_pypeline-2.1.
|
34
|
-
scalable_pypeline-2.1.
|
35
|
-
scalable_pypeline-2.1.
|
36
|
-
scalable_pypeline-2.1.
|
37
|
-
scalable_pypeline-2.1.
|
32
|
+
scalable_pypeline-2.1.10.dist-info/LICENSE,sha256=DVQuDIgE45qn836wDaWnYhSdxoLXgpRRKH4RuTjpRZQ,10174
|
33
|
+
scalable_pypeline-2.1.10.dist-info/METADATA,sha256=FbXEulwsHZccTmDU7WkEgoO4kPS2z6xAt-29n3gsl6g,5927
|
34
|
+
scalable_pypeline-2.1.10.dist-info/WHEEL,sha256=bb2Ot9scclHKMOLDEHY6B2sicWOgugjFKaJsT7vwMQo,110
|
35
|
+
scalable_pypeline-2.1.10.dist-info/entry_points.txt,sha256=uWs10ODfHSBKo2Cx_QaUjPHQTpZ3e77j9VlAdRRmMyg,119
|
36
|
+
scalable_pypeline-2.1.10.dist-info/top_level.txt,sha256=C7dpkEOc_-nnsAQb28BfQknjD6XHRyS9ZrvVeoIbV7s,15
|
37
|
+
scalable_pypeline-2.1.10.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|