scalable-pypeline 2.1.9__tar.gz → 2.1.11__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.
- {scalable-pypeline-2.1.9/scalable_pypeline.egg-info → scalable-pypeline-2.1.11}/PKG-INFO +1 -1
- scalable-pypeline-2.1.11/pypeline/__init__.py +1 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/dramatiq.py +43 -37
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/pipeline_config_schema.py +17 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/pipelines/composition/pypeline_composition.py +4 -1
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/pipelines/factory.py +2 -1
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/pipelines/middleware/pypeline_middleware.py +21 -11
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/utils/dramatiq_utils.py +6 -2
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11/scalable_pypeline.egg-info}/PKG-INFO +1 -1
- scalable-pypeline-2.1.9/pypeline/__init__.py +0 -1
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/LICENSE +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/MANIFEST.in +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/README.md +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/barrier.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/constants.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/extensions.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/flask/__init__.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/flask/api/__init__.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/flask/api/pipelines.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/flask/api/schedules.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/flask/decorators.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/flask/flask_pypeline.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/pipeline_settings_schema.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/pipelines/__init__.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/pipelines/composition/__init__.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/pipelines/composition/parallel_pipeline_composition.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/pipelines/middleware/__init__.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/pipelines/middleware/get_active_worker_id_middleware.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/pipelines/middleware/parallel_pipeline_middleware.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/pypeline_yaml.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/schedule_config_schema.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/utils/__init__.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/utils/config_utils.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/utils/module_utils.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/utils/pipeline_utils.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/utils/schema_utils.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/requirements.txt +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/scalable_pypeline.egg-info/SOURCES.txt +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/scalable_pypeline.egg-info/dependency_links.txt +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/scalable_pypeline.egg-info/entry_points.txt +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/scalable_pypeline.egg-info/requires.txt +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/scalable_pypeline.egg-info/top_level.txt +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/setup.cfg +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/setup.py +0 -0
- {scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/tests/fixtures/__init__.py +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "2.1.11"
|
@@ -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
|
@@ -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()
|
@@ -50,16 +48,16 @@ class PypelineMiddleware(Middleware):
|
|
50
48
|
|
51
49
|
messages = []
|
52
50
|
for child in children_tasks:
|
53
|
-
child_ancestors = sorted(
|
51
|
+
child_ancestors = sorted(graph.predecessors(child))
|
54
52
|
|
55
53
|
ancestor_tasks_complete = True
|
56
54
|
|
57
55
|
for ancestor in child_ancestors:
|
58
|
-
|
56
|
+
ancestor_task_key = f"{execution_id}-{ancestor}"
|
59
57
|
|
60
58
|
locking_parallel_barrier = LockingParallelBarrier(
|
61
59
|
self.redis_url,
|
62
|
-
task_key=
|
60
|
+
task_key=ancestor_task_key,
|
63
61
|
lock_key=f"{message.options['base_case_execution_id']}-lock",
|
64
62
|
)
|
65
63
|
try:
|
@@ -74,12 +72,17 @@ class PypelineMiddleware(Middleware):
|
|
74
72
|
finally:
|
75
73
|
locking_parallel_barrier.release_lock()
|
76
74
|
|
77
|
-
|
78
|
-
|
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
|
78
|
+
if remaining_tasks is None:
|
79
|
+
ancestor_task_key = (
|
80
|
+
f"{message.options['base_case_execution_id']}-{ancestor}"
|
81
|
+
)
|
79
82
|
|
80
83
|
locking_parallel_barrier = LockingParallelBarrier(
|
81
84
|
self.redis_url,
|
82
|
-
task_key=
|
85
|
+
task_key=ancestor_task_key,
|
83
86
|
lock_key=f"{message.options['base_case_execution_id']}-lock",
|
84
87
|
)
|
85
88
|
try:
|
@@ -95,7 +98,7 @@ class PypelineMiddleware(Middleware):
|
|
95
98
|
)
|
96
99
|
finally:
|
97
100
|
locking_parallel_barrier.release_lock()
|
98
|
-
if remaining_tasks >= 1:
|
101
|
+
if remaining_tasks is None or remaining_tasks >= 1:
|
99
102
|
ancestor_tasks_complete = False
|
100
103
|
break
|
101
104
|
|
@@ -103,6 +106,7 @@ class PypelineMiddleware(Middleware):
|
|
103
106
|
if not ancestor_tasks_complete:
|
104
107
|
break
|
105
108
|
|
109
|
+
# Handle situation where base case kicks off new scenario
|
106
110
|
if (
|
107
111
|
message.options["base_case_execution_id"]
|
108
112
|
== message.options["execution_id"]
|
@@ -124,11 +128,13 @@ class PypelineMiddleware(Middleware):
|
|
124
128
|
handler = task_definitions[child]["handlers"][
|
125
129
|
task_replacements.get(child, 0)
|
126
130
|
]
|
131
|
+
server_type = task_definitions[child].get("serverType", None)
|
127
132
|
|
128
133
|
lazy_actor = register_lazy_actor(
|
129
134
|
broker,
|
130
135
|
get_callable(handler),
|
131
136
|
pipeline_config["metadata"],
|
137
|
+
server_type,
|
132
138
|
)
|
133
139
|
scenario_message = lazy_actor.message()
|
134
140
|
scenario_message.options["pipeline"] = pipeline
|
@@ -154,6 +160,8 @@ class PypelineMiddleware(Middleware):
|
|
154
160
|
scenario["execution_id"]
|
155
161
|
)
|
156
162
|
messages.append(scenario_message)
|
163
|
+
|
164
|
+
# Kick off child task for current scenario
|
157
165
|
task_key = f"{execution_id}-{child}"
|
158
166
|
locking_parallel_barrier = LockingParallelBarrier(
|
159
167
|
self.redis_url,
|
@@ -164,10 +172,12 @@ class PypelineMiddleware(Middleware):
|
|
164
172
|
handler = task_definitions[child]["handlers"][
|
165
173
|
task_replacements.get(child, 0)
|
166
174
|
]
|
175
|
+
server_type = task_definitions[child].get("serverType", None)
|
167
176
|
lazy_actor = register_lazy_actor(
|
168
177
|
broker,
|
169
178
|
get_callable(handler),
|
170
179
|
pipeline_config["metadata"],
|
180
|
+
server_type,
|
171
181
|
)
|
172
182
|
|
173
183
|
child_message = lazy_actor.message()
|
@@ -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 +0,0 @@
|
|
1
|
-
__version__ = "2.1.9"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/pipelines/composition/__init__.py
RENAMED
File without changes
|
File without changes
|
{scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/pypeline/pipelines/middleware/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/scalable_pypeline.egg-info/dependency_links.txt
RENAMED
File without changes
|
{scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/scalable_pypeline.egg-info/entry_points.txt
RENAMED
File without changes
|
{scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/scalable_pypeline.egg-info/requires.txt
RENAMED
File without changes
|
{scalable-pypeline-2.1.9 → scalable-pypeline-2.1.11}/scalable_pypeline.egg-info/top_level.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|