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 CHANGED
@@ -1 +1 @@
1
- __version__ = "2.1.9"
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
- for task in service.get("registeredTasks", []):
105
- pipeline_meta = None
106
- for pipeline_key, pipeline in pypeline_config["pipelines"].items():
107
- pipeline_config = pipeline["config"]
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
- pipeline_tasks = [
110
- t["handler"] for t in pipeline_config["taskDefinitions"].values()
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
- pipeline_tasks = [
114
- handler
115
- for key in pipeline_config["taskDefinitions"]
116
- for handler in pipeline_config["taskDefinitions"][key].get(
117
- "handlers", []
118
- )
119
- ]
120
- if task["handler"] in pipeline_tasks:
121
- pipeline_meta = pipeline_config["metadata"]
122
- break
123
-
124
- if pipeline_meta is None:
125
- for job in scheduled_jobs_config:
126
- config = job["config"]
127
- if config["task"] == task["handler"]:
128
- pipeline_meta = {"queue": config.get("queue", "default")}
129
-
130
- if pipeline_meta is None:
131
- raise ValueError(
132
- f"Registered task {task['handler']} is not defined in a pipeline or scheduled task"
133
- )
134
-
135
- try:
136
- worker_path = task["handler"] # Required, no default
137
- tmp_handler = get_callable(worker_path)
138
- if pipeline_meta and pipeline_meta.get("maxRetry", 0) >= 0:
139
- pipeline_meta["store_results"] = True
140
- _ = register_lazy_actor(broker, tmp_handler, pipeline_meta)
141
- except Exception as e:
142
- logger.exception(f"Unable to add a task to dramatiq: {e}")
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 job is finished
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()
@@ -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
- kwargs["queue_name"] = pipeline_meta.get("queue", "default")
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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: scalable-pypeline
3
- Version: 2.1.9
3
+ Version: 2.1.10
4
4
  Summary: PypeLine - Python pipelines for the Real World
5
5
  Home-page: https://gitlab.com/bravos2/pypeline
6
6
  Author: Bravos Power Corporation
@@ -1,9 +1,9 @@
1
- pypeline/__init__.py,sha256=Gf0zUMmdRLkPmvwnoP7oCpWn7Ep93jlNIlBD6nifugI,22
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=5whdOQjzknLjl9lYNj5-f2jRw5ysRPhQExi5NN4KeOY,12837
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=hK2_egtg-YFx_XJDs_NyrOTGKkel7W83X-G0sic52sM,10592
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=356v1S0WPvDkd9f0fKk0H9aXVbOqQYSWt47aOl66EKk,3172
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=UBuDKEfRoIbL-9c-HH2ZTVbzfkwFSlNoFH-AVNqt0QE,7965
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=IXVqzcOlSJ43lsn-i298RkaeygB-PTJjsvdTDtpgfwg,8141
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=5GDcOvKY-8S8r---wb6Q8QAywhbKVJ-qILjcYNHei8Y,3658
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.9.dist-info/LICENSE,sha256=DVQuDIgE45qn836wDaWnYhSdxoLXgpRRKH4RuTjpRZQ,10174
33
- scalable_pypeline-2.1.9.dist-info/METADATA,sha256=H96u1H3mZdGCb1yfmo52azC_BiVq0rzo2nBYTViHElk,5926
34
- scalable_pypeline-2.1.9.dist-info/WHEEL,sha256=bb2Ot9scclHKMOLDEHY6B2sicWOgugjFKaJsT7vwMQo,110
35
- scalable_pypeline-2.1.9.dist-info/entry_points.txt,sha256=uWs10ODfHSBKo2Cx_QaUjPHQTpZ3e77j9VlAdRRmMyg,119
36
- scalable_pypeline-2.1.9.dist-info/top_level.txt,sha256=C7dpkEOc_-nnsAQb28BfQknjD6XHRyS9ZrvVeoIbV7s,15
37
- scalable_pypeline-2.1.9.dist-info/RECORD,,
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,,