runnable 0.14.0__py3-none-any.whl → 0.17.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- runnable/__init__.py +1 -1
- runnable/catalog.py +2 -0
- runnable/cli.py +264 -307
- runnable/context.py +12 -3
- runnable/datastore.py +159 -25
- runnable/defaults.py +13 -54
- runnable/entrypoints.py +197 -185
- runnable/exceptions.py +22 -0
- runnable/executor.py +114 -88
- runnable/graph.py +0 -1
- runnable/nodes.py +36 -6
- runnable/sdk.py +132 -36
- runnable/tasks.py +6 -15
- runnable/utils.py +22 -30
- {runnable-0.14.0.dist-info → runnable-0.17.0.dist-info}/METADATA +6 -3
- runnable-0.17.0.dist-info/RECORD +23 -0
- {runnable-0.14.0.dist-info → runnable-0.17.0.dist-info}/entry_points.txt +12 -7
- runnable/integration.py +0 -197
- runnable-0.14.0.dist-info/RECORD +0 -24
- {runnable-0.14.0.dist-info → runnable-0.17.0.dist-info}/WHEEL +0 -0
- {runnable-0.14.0.dist-info → runnable-0.17.0.dist-info}/licenses/LICENSE +0 -0
runnable/entrypoints.py
CHANGED
@@ -9,12 +9,16 @@ from rich.progress import BarColumn, Progress, TextColumn, TimeElapsedColumn
|
|
9
9
|
from rich.table import Column
|
10
10
|
|
11
11
|
import runnable.context as context
|
12
|
-
from runnable import console, defaults, graph, task_console, utils
|
12
|
+
from runnable import console, defaults, graph, task_console, tasks, utils
|
13
13
|
from runnable.defaults import RunnableConfig, ServiceConfig
|
14
|
+
from runnable.executor import BaseJobExecutor, BasePipelineExecutor
|
14
15
|
|
15
16
|
logger = logging.getLogger(defaults.LOGGER_NAME)
|
16
17
|
|
17
18
|
|
19
|
+
print("") # removes the buffer print
|
20
|
+
|
21
|
+
|
18
22
|
def get_default_configs() -> RunnableConfig:
|
19
23
|
"""
|
20
24
|
User can provide extensions as part of their code base, runnable-config.yaml provides the place to put them.
|
@@ -29,10 +33,9 @@ def get_default_configs() -> RunnableConfig:
|
|
29
33
|
def prepare_configurations(
|
30
34
|
run_id: str,
|
31
35
|
configuration_file: str = "",
|
32
|
-
pipeline_file: str = "",
|
33
36
|
tag: str = "",
|
34
37
|
parameters_file: str = "",
|
35
|
-
|
38
|
+
is_job: bool = False,
|
36
39
|
) -> context.Context:
|
37
40
|
"""
|
38
41
|
Sets up everything needed
|
@@ -42,7 +45,6 @@ def prepare_configurations(
|
|
42
45
|
|
43
46
|
Args:
|
44
47
|
variables_file (str): The variables file, if used or None
|
45
|
-
pipeline_file (str): The config/dag file
|
46
48
|
run_id (str): The run id of the run.
|
47
49
|
tag (str): If a tag is provided at the run time
|
48
50
|
|
@@ -59,22 +61,26 @@ def prepare_configurations(
|
|
59
61
|
)
|
60
62
|
|
61
63
|
if configuration_file:
|
62
|
-
templated_configuration = utils.load_yaml(configuration_file)
|
64
|
+
templated_configuration = utils.load_yaml(configuration_file)
|
65
|
+
|
66
|
+
# apply variables
|
67
|
+
configuration = cast(
|
68
|
+
RunnableConfig, utils.apply_variables(templated_configuration, variables)
|
69
|
+
)
|
63
70
|
|
64
71
|
# Since all the services (run_log_store, catalog, secrets, executor) are
|
65
72
|
# dynamically loaded via stevedore, we cannot validate the configuration
|
66
73
|
# before they are passed to the service.
|
67
74
|
|
68
|
-
configuration: RunnableConfig = cast(RunnableConfig, templated_configuration)
|
69
|
-
|
70
75
|
logger.info(f"Resolved configurations: {configuration}")
|
71
76
|
|
72
77
|
# Run log settings, configuration over-rides everything
|
73
|
-
|
78
|
+
# The user config has run-log-store while internally we use run_log_store
|
79
|
+
run_log_config: Optional[ServiceConfig] = configuration.get("run-log-store", None) # type: ignore
|
74
80
|
if not run_log_config:
|
75
81
|
run_log_config = cast(
|
76
82
|
ServiceConfig,
|
77
|
-
runnable_defaults.get("
|
83
|
+
runnable_defaults.get("run-log-store", defaults.DEFAULT_RUN_LOG_STORE),
|
78
84
|
)
|
79
85
|
run_log_store = utils.get_provider_by_name_and_type("run_log_store", run_log_config)
|
80
86
|
|
@@ -100,18 +106,37 @@ def prepare_configurations(
|
|
100
106
|
)
|
101
107
|
pickler_handler = utils.get_provider_by_name_and_type("pickler", pickler_config)
|
102
108
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
109
|
+
if not is_job:
|
110
|
+
# executor configurations, configuration over rides everything
|
111
|
+
executor_config: Optional[ServiceConfig] = configuration.get(
|
112
|
+
"pipeline-executor", None
|
113
|
+
) # type: ignore
|
114
|
+
# as pipeline-executor is not a valid key
|
115
|
+
if not executor_config:
|
116
|
+
executor_config = cast(
|
117
|
+
ServiceConfig,
|
118
|
+
runnable_defaults.get(
|
119
|
+
"pipeline-executor", defaults.DEFAULT_PIPELINE_EXECUTOR
|
120
|
+
),
|
121
|
+
)
|
122
|
+
configured_executor = utils.get_provider_by_name_and_type(
|
123
|
+
"pipeline_executor", executor_config
|
124
|
+
)
|
125
|
+
else:
|
126
|
+
# executor configurations, configuration over rides everything
|
127
|
+
job_executor_config: Optional[ServiceConfig] = configuration.get(
|
128
|
+
"job-executor", None
|
129
|
+
) # type: ignore
|
130
|
+
if not job_executor_config:
|
131
|
+
executor_config = cast(
|
132
|
+
ServiceConfig,
|
133
|
+
runnable_defaults.get("job-executor", defaults.DEFAULT_JOB_EXECUTOR),
|
134
|
+
)
|
107
135
|
|
108
|
-
|
109
|
-
|
110
|
-
|
136
|
+
assert job_executor_config, "Job executor is not provided"
|
137
|
+
configured_executor = utils.get_provider_by_name_and_type(
|
138
|
+
"job_executor", job_executor_config
|
111
139
|
)
|
112
|
-
configured_executor = utils.get_provider_by_name_and_type(
|
113
|
-
"executor", executor_config
|
114
|
-
)
|
115
140
|
|
116
141
|
# Construct the context
|
117
142
|
run_context = context.Context(
|
@@ -127,38 +152,45 @@ def prepare_configurations(
|
|
127
152
|
parameters_file=parameters_file,
|
128
153
|
)
|
129
154
|
|
130
|
-
|
131
|
-
if pipeline_file.endswith(".py"):
|
132
|
-
# converting a pipeline defined in python to a dag in yaml
|
133
|
-
module_file = pipeline_file.strip(".py")
|
134
|
-
module, func = utils.get_module_and_attr_names(module_file)
|
135
|
-
sys.path.insert(0, os.getcwd()) # Need to add the current directory to path
|
136
|
-
imported_module = importlib.import_module(module)
|
155
|
+
context.run_context = run_context
|
137
156
|
|
138
|
-
|
139
|
-
dag = getattr(imported_module, func)().return_dag()
|
157
|
+
return run_context
|
140
158
|
|
141
|
-
else:
|
142
|
-
pipeline_config = utils.load_yaml(pipeline_file)
|
143
159
|
|
144
|
-
|
145
|
-
|
160
|
+
def set_pipeline_spec_from_yaml(run_context: context.Context, pipeline_file: str):
|
161
|
+
"""
|
162
|
+
Reads the pipeline file from a YAML file and sets the pipeline spec in the run context
|
163
|
+
"""
|
164
|
+
pipeline_config = utils.load_yaml(pipeline_file)
|
165
|
+
logger.info("The input pipeline:")
|
166
|
+
logger.info(json.dumps(pipeline_config, indent=4))
|
146
167
|
|
147
|
-
|
168
|
+
dag_config = pipeline_config["dag"]
|
148
169
|
|
149
|
-
|
150
|
-
|
151
|
-
|
170
|
+
dag_hash = utils.get_dag_hash(dag_config)
|
171
|
+
dag = graph.create_graph(dag_config)
|
172
|
+
run_context.dag_hash = dag_hash
|
152
173
|
|
153
|
-
|
154
|
-
|
174
|
+
run_context.pipeline_file = pipeline_file
|
175
|
+
run_context.dag = dag
|
155
176
|
|
156
|
-
context.run_context = run_context
|
157
177
|
|
158
|
-
|
178
|
+
def set_pipeline_spec_from_python(run_context: context.Context, python_module: str):
|
179
|
+
# Call the SDK to get the dag
|
180
|
+
# Import the module and call the function to get the dag
|
181
|
+
module_file = python_module.strip(".py")
|
182
|
+
module, func = utils.get_module_and_attr_names(module_file)
|
183
|
+
sys.path.insert(0, os.getcwd()) # Need to add the current directory to path
|
184
|
+
imported_module = importlib.import_module(module)
|
185
|
+
|
186
|
+
run_context.from_sdk = True
|
187
|
+
dag = getattr(imported_module, func)().return_dag()
|
188
|
+
|
189
|
+
run_context.pipeline_file = python_module
|
190
|
+
run_context.dag = dag
|
159
191
|
|
160
192
|
|
161
|
-
def
|
193
|
+
def execute_pipeline_yaml_spec(
|
162
194
|
pipeline_file: str,
|
163
195
|
configuration_file: str = "",
|
164
196
|
tag: str = "",
|
@@ -167,39 +199,35 @@ def execute(
|
|
167
199
|
):
|
168
200
|
# pylint: disable=R0914,R0913
|
169
201
|
"""
|
170
|
-
The entry point to runnable execution
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
pipeline_file (str): The config/dag file
|
175
|
-
run_id (str): The run id of the run.
|
176
|
-
tag (str): If a tag is provided at the run time
|
177
|
-
parameters_file (str): The parameters being sent in to the application
|
202
|
+
The entry point to runnable execution for any YAML based spec.
|
203
|
+
The result could:
|
204
|
+
- Execution of the pipeline if its local executor
|
205
|
+
- Rendering of the spec in the case of non local executor
|
178
206
|
"""
|
179
207
|
run_id = utils.generate_run_id(run_id=run_id)
|
180
208
|
|
181
209
|
run_context = prepare_configurations(
|
182
210
|
configuration_file=configuration_file,
|
183
|
-
pipeline_file=pipeline_file,
|
184
211
|
run_id=run_id,
|
185
212
|
tag=tag,
|
186
213
|
parameters_file=parameters_file,
|
187
214
|
)
|
188
215
|
|
189
|
-
|
190
|
-
console.print(run_context)
|
191
|
-
console.rule(style="[dark orange]")
|
216
|
+
assert isinstance(run_context.executor, BasePipelineExecutor)
|
192
217
|
|
218
|
+
set_pipeline_spec_from_yaml(run_context, pipeline_file)
|
193
219
|
executor = run_context.executor
|
194
220
|
|
195
|
-
run_context.execution_plan = defaults.EXECUTION_PLAN.CHAINED.value
|
196
|
-
|
197
221
|
utils.set_runnable_environment_variables(
|
198
222
|
run_id=run_id, configuration_file=configuration_file, tag=tag
|
199
223
|
)
|
200
224
|
|
201
225
|
# Prepare for graph execution
|
202
|
-
executor.
|
226
|
+
executor._set_up_run_log(exists_ok=False)
|
227
|
+
|
228
|
+
console.print("Working with context:")
|
229
|
+
console.print(run_context)
|
230
|
+
console.rule(style="[dark orange]")
|
203
231
|
|
204
232
|
logger.info(f"Executing the graph: {run_context.dag}")
|
205
233
|
with Progress(
|
@@ -218,8 +246,8 @@ def execute(
|
|
218
246
|
run_context.progress = progress
|
219
247
|
executor.execute_graph(dag=run_context.dag) # type: ignore
|
220
248
|
|
221
|
-
|
222
|
-
|
249
|
+
if not executor._is_local:
|
250
|
+
# Non local executors only traverse the graph and do not execute the nodes
|
223
251
|
executor.send_return_code(stage="traversal")
|
224
252
|
return
|
225
253
|
|
@@ -259,24 +287,18 @@ def execute_single_node(
|
|
259
287
|
pipeline_file: str,
|
260
288
|
step_name: str,
|
261
289
|
map_variable: str,
|
290
|
+
mode: str,
|
262
291
|
run_id: str,
|
263
292
|
tag: str = "",
|
264
293
|
parameters_file: str = "",
|
265
294
|
):
|
266
295
|
"""
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
It should have similar set up of configurations to execute because orchestrator modes can initiate the execution.
|
271
|
-
|
272
|
-
Args:
|
273
|
-
variables_file (str): The variables file, if used or None
|
274
|
-
step_name : The name of the step to execute in dot path convention
|
275
|
-
pipeline_file (str): The config/dag file
|
276
|
-
run_id (str): The run id of the run.
|
277
|
-
tag (str): If a tag is provided at the run time
|
278
|
-
parameters_file (str): The parameters being sent in to the application
|
296
|
+
This entry point is triggered during the execution of the pipeline
|
297
|
+
- non local execution environments
|
279
298
|
|
299
|
+
The mode defines how the pipeline spec is provided to the runnable
|
300
|
+
- yaml
|
301
|
+
- python
|
280
302
|
"""
|
281
303
|
from runnable import nodes
|
282
304
|
|
@@ -290,30 +312,30 @@ def execute_single_node(
|
|
290
312
|
|
291
313
|
run_context = prepare_configurations(
|
292
314
|
configuration_file=configuration_file,
|
293
|
-
pipeline_file=pipeline_file,
|
294
315
|
run_id=run_id,
|
295
316
|
tag=tag,
|
296
317
|
parameters_file=parameters_file,
|
297
318
|
)
|
319
|
+
assert isinstance(run_context.executor, BasePipelineExecutor)
|
320
|
+
|
321
|
+
if mode == "yaml":
|
322
|
+
# Load the yaml file
|
323
|
+
set_pipeline_spec_from_yaml(run_context, pipeline_file)
|
324
|
+
elif mode == "python":
|
325
|
+
# Call the SDK to get the dag
|
326
|
+
set_pipeline_spec_from_python(run_context, pipeline_file)
|
327
|
+
|
328
|
+
assert run_context.dag
|
329
|
+
|
298
330
|
task_console.print("Working with context:")
|
299
331
|
task_console.print(run_context)
|
300
332
|
task_console.rule(style="[dark orange]")
|
301
333
|
|
302
334
|
executor = run_context.executor
|
303
|
-
run_context.execution_plan = defaults.EXECUTION_PLAN.CHAINED.value
|
304
335
|
utils.set_runnable_environment_variables(
|
305
336
|
run_id=run_id, configuration_file=configuration_file, tag=tag
|
306
337
|
)
|
307
338
|
|
308
|
-
executor.prepare_for_node_execution()
|
309
|
-
|
310
|
-
# TODO: may be make its own entry point
|
311
|
-
# if not run_context.dag:
|
312
|
-
# # There are a few entry points that make graph dynamically and do not have a dag defined statically.
|
313
|
-
# run_log = run_context.run_log_store.get_run_log_by_id(run_id=run_id, full=False)
|
314
|
-
# run_context.dag = graph.create_graph(run_log.run_config["pipeline"])
|
315
|
-
assert run_context.dag
|
316
|
-
|
317
339
|
map_variable_dict = utils.json_to_ordered_dict(map_variable)
|
318
340
|
|
319
341
|
step_internal_name = nodes.BaseNode._get_internal_name_from_command_name(step_name)
|
@@ -322,7 +344,7 @@ def execute_single_node(
|
|
322
344
|
)
|
323
345
|
|
324
346
|
logger.info("Executing the single node of : %s", node_to_execute)
|
325
|
-
## This step is where we save the
|
347
|
+
## This step is where we save output of the function/shell command
|
326
348
|
try:
|
327
349
|
executor.execute_node(node=node_to_execute, map_variable=map_variable_dict)
|
328
350
|
finally:
|
@@ -336,23 +358,15 @@ def execute_single_node(
|
|
336
358
|
run_context.catalog_handler.put(name=log_file_name, run_id=run_context.run_id)
|
337
359
|
os.remove(log_file_name)
|
338
360
|
|
339
|
-
# executor.send_return_code(stage="execution")
|
340
|
-
|
341
361
|
|
342
|
-
def
|
343
|
-
|
344
|
-
|
345
|
-
catalog_config: dict,
|
346
|
-
configuration_file: str,
|
347
|
-
notebook_output_path: str = "",
|
362
|
+
def execute_job_yaml_spec(
|
363
|
+
job_definition_file: str,
|
364
|
+
configuration_file: str = "",
|
348
365
|
tag: str = "",
|
349
366
|
run_id: str = "",
|
350
367
|
parameters_file: str = "",
|
351
368
|
):
|
352
|
-
|
353
|
-
The entry point to runnable execution of a notebook. This method would prepare the configurations and
|
354
|
-
delegates traversal to the executor
|
355
|
-
"""
|
369
|
+
# A job and task are internally the same.
|
356
370
|
run_id = utils.generate_run_id(run_id=run_id)
|
357
371
|
|
358
372
|
run_context = prepare_configurations(
|
@@ -360,71 +374,87 @@ def execute_notebook(
|
|
360
374
|
run_id=run_id,
|
361
375
|
tag=tag,
|
362
376
|
parameters_file=parameters_file,
|
377
|
+
is_job=True,
|
363
378
|
)
|
364
379
|
|
380
|
+
assert isinstance(run_context.executor, BaseJobExecutor)
|
381
|
+
|
365
382
|
executor = run_context.executor
|
366
|
-
run_context.execution_plan = defaults.EXECUTION_PLAN.UNCHAINED.value
|
367
383
|
utils.set_runnable_environment_variables(
|
368
384
|
run_id=run_id, configuration_file=configuration_file, tag=tag
|
369
385
|
)
|
370
386
|
|
387
|
+
run_context.job_definition_file = job_definition_file
|
388
|
+
|
389
|
+
job_config = utils.load_yaml(job_definition_file)
|
390
|
+
logger.info(
|
391
|
+
"Executing the job from the user."
|
392
|
+
f"job definition: {job_definition_file}, config: {job_config}"
|
393
|
+
)
|
394
|
+
assert job_config.get("type"), "Job type is not provided"
|
395
|
+
|
371
396
|
console.print("Working with context:")
|
372
397
|
console.print(run_context)
|
373
398
|
console.rule(style="[dark orange]")
|
374
399
|
|
375
|
-
|
376
|
-
|
377
|
-
"command_type": "notebook",
|
378
|
-
"notebook_output_path": notebook_output_path,
|
379
|
-
"type": "task",
|
380
|
-
"next": "success",
|
381
|
-
"catalog": catalog_config,
|
382
|
-
}
|
383
|
-
node = graph.create_node(name="executing job", step_config=step_config)
|
384
|
-
|
385
|
-
if entrypoint == defaults.ENTRYPOINT.USER.value:
|
386
|
-
# Prepare for graph execution
|
387
|
-
executor.prepare_for_graph_execution()
|
388
|
-
|
389
|
-
logger.info(
|
390
|
-
"Executing the job from the user. We are still in the caller's compute environment"
|
391
|
-
)
|
392
|
-
executor.execute_job(node=node)
|
400
|
+
# A hack where we create a task node and get our job/catalog settings
|
401
|
+
catalog_config: list[str] = job_config.pop("catalog", {})
|
393
402
|
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
"Executing the job from the system. We are in the config's compute environment"
|
398
|
-
)
|
399
|
-
executor.execute_node(node=node)
|
403
|
+
# rename the type to command_type of task
|
404
|
+
job_config["command_type"] = job_config.pop("type")
|
405
|
+
job = tasks.create_task(job_config)
|
400
406
|
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
)
|
405
|
-
run_context.run_log_store.update_run_log_status(
|
406
|
-
run_id=run_id, status=step_log.status
|
407
|
-
)
|
407
|
+
logger.info(
|
408
|
+
"Executing the job from the user. We are still in the caller's compute environment"
|
409
|
+
)
|
408
410
|
|
409
|
-
|
410
|
-
|
411
|
+
assert isinstance(executor, BaseJobExecutor)
|
412
|
+
executor.submit_job(job, catalog_settings=catalog_config)
|
411
413
|
|
412
414
|
executor.send_return_code()
|
413
415
|
|
414
416
|
|
415
|
-
def
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
417
|
+
def set_job_spec_from_yaml(run_context: context.Context, job_definition_file: str):
|
418
|
+
"""
|
419
|
+
Reads the pipeline file from a YAML file and sets the pipeline spec in the run context
|
420
|
+
"""
|
421
|
+
job_config = utils.load_yaml(job_definition_file)
|
422
|
+
logger.info("The input job definition file:")
|
423
|
+
logger.info(json.dumps(job_config, indent=4))
|
424
|
+
|
425
|
+
catalog_config: list[str] = job_config.pop("catalog", {})
|
426
|
+
|
427
|
+
job_config["command_type"] = job_config.pop("type")
|
428
|
+
|
429
|
+
run_context.job_definition_file = job_definition_file
|
430
|
+
run_context.job = tasks.create_task(job_config)
|
431
|
+
run_context.job_catalog_settings = catalog_config
|
432
|
+
|
433
|
+
|
434
|
+
def set_job_spec_from_python(run_context: context.Context, python_module: str):
|
435
|
+
# Import the module and call the function to get the task
|
436
|
+
module_file = python_module.strip(".py")
|
437
|
+
module, func = utils.get_module_and_attr_names(module_file)
|
438
|
+
sys.path.insert(0, os.getcwd()) # Need to add the current directory to path
|
439
|
+
imported_module = importlib.import_module(module)
|
440
|
+
|
441
|
+
run_context.from_sdk = True
|
442
|
+
task = getattr(imported_module, func)().return_task()
|
443
|
+
catalog_settings = getattr(imported_module, func)().return_catalog_settings()
|
444
|
+
|
445
|
+
run_context.job_definition_file = python_module
|
446
|
+
run_context.job = task
|
447
|
+
run_context.job_catalog_settings = catalog_settings
|
448
|
+
|
449
|
+
|
450
|
+
def execute_job_non_local(
|
451
|
+
job_definition_file: str,
|
452
|
+
configuration_file: str = "",
|
453
|
+
mode: str = "yaml",
|
420
454
|
tag: str = "",
|
421
455
|
run_id: str = "",
|
422
456
|
parameters_file: str = "",
|
423
457
|
):
|
424
|
-
"""
|
425
|
-
The entry point to runnable execution of a function. This method would prepare the configurations and
|
426
|
-
delegates traversal to the executor
|
427
|
-
"""
|
428
458
|
run_id = utils.generate_run_id(run_id=run_id)
|
429
459
|
|
430
460
|
run_context = prepare_configurations(
|
@@ -432,57 +462,33 @@ def execute_function(
|
|
432
462
|
run_id=run_id,
|
433
463
|
tag=tag,
|
434
464
|
parameters_file=parameters_file,
|
465
|
+
is_job=True,
|
435
466
|
)
|
436
467
|
|
437
|
-
|
468
|
+
assert isinstance(run_context.executor, BaseJobExecutor)
|
438
469
|
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
470
|
+
if mode == "yaml":
|
471
|
+
# Load the yaml file
|
472
|
+
set_job_spec_from_yaml(run_context, job_definition_file)
|
473
|
+
elif mode == "python":
|
474
|
+
# Call the SDK to get the task
|
475
|
+
set_job_spec_from_python(run_context, job_definition_file)
|
476
|
+
|
477
|
+
assert run_context.job
|
443
478
|
|
444
479
|
console.print("Working with context:")
|
445
480
|
console.print(run_context)
|
446
481
|
console.rule(style="[dark orange]")
|
447
482
|
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
"command_type": "python",
|
452
|
-
"type": "task",
|
453
|
-
"next": "success",
|
454
|
-
"catalog": catalog_config,
|
455
|
-
}
|
456
|
-
node = graph.create_node(name="executing job", step_config=step_config)
|
457
|
-
|
458
|
-
if entrypoint == defaults.ENTRYPOINT.USER.value:
|
459
|
-
# Prepare for graph execution
|
460
|
-
executor.prepare_for_graph_execution()
|
461
|
-
|
462
|
-
logger.info(
|
463
|
-
"Executing the job from the user. We are still in the caller's compute environment"
|
464
|
-
)
|
465
|
-
executor.execute_job(node=node)
|
466
|
-
|
467
|
-
elif entrypoint == defaults.ENTRYPOINT.SYSTEM.value:
|
468
|
-
executor.prepare_for_node_execution()
|
469
|
-
logger.info(
|
470
|
-
"Executing the job from the system. We are in the config's compute environment"
|
471
|
-
)
|
472
|
-
executor.execute_node(node=node)
|
473
|
-
|
474
|
-
# Update the status of the run log
|
475
|
-
step_log = run_context.run_log_store.get_step_log(
|
476
|
-
node._get_step_log_name(), run_id
|
477
|
-
)
|
478
|
-
run_context.run_log_store.update_run_log_status(
|
479
|
-
run_id=run_id, status=step_log.status
|
480
|
-
)
|
483
|
+
logger.info(
|
484
|
+
"Executing the job from the user. We are still in the caller's compute environment"
|
485
|
+
)
|
481
486
|
|
482
|
-
|
483
|
-
|
487
|
+
run_context.executor.execute_job(
|
488
|
+
run_context.job, catalog_settings=run_context.job_catalog_settings
|
489
|
+
)
|
484
490
|
|
485
|
-
executor.send_return_code()
|
491
|
+
run_context.executor.send_return_code()
|
486
492
|
|
487
493
|
|
488
494
|
def fan(
|
@@ -518,23 +524,29 @@ def fan(
|
|
518
524
|
|
519
525
|
run_context = prepare_configurations(
|
520
526
|
configuration_file=configuration_file,
|
521
|
-
pipeline_file=pipeline_file,
|
522
527
|
run_id=run_id,
|
523
528
|
tag=tag,
|
524
529
|
parameters_file=parameters_file,
|
525
530
|
)
|
531
|
+
|
532
|
+
assert isinstance(run_context.executor, BasePipelineExecutor)
|
533
|
+
|
534
|
+
if mode == "yaml":
|
535
|
+
# Load the yaml file
|
536
|
+
set_pipeline_spec_from_yaml(run_context, pipeline_file)
|
537
|
+
elif mode == "python":
|
538
|
+
# Call the SDK to get the dag
|
539
|
+
set_pipeline_spec_from_python(run_context, pipeline_file)
|
540
|
+
|
526
541
|
console.print("Working with context:")
|
527
542
|
console.print(run_context)
|
528
543
|
console.rule(style="[dark orange]")
|
529
544
|
|
530
545
|
executor = run_context.executor
|
531
|
-
run_context.execution_plan = defaults.EXECUTION_PLAN.CHAINED.value
|
532
546
|
utils.set_runnable_environment_variables(
|
533
547
|
run_id=run_id, configuration_file=configuration_file, tag=tag
|
534
548
|
)
|
535
549
|
|
536
|
-
executor.prepare_for_node_execution()
|
537
|
-
|
538
550
|
step_internal_name = nodes.BaseNode._get_internal_name_from_command_name(step_name)
|
539
551
|
node_to_execute, _ = graph.search_node_by_internal_name(
|
540
552
|
run_context.dag, # type: ignore
|
@@ -553,6 +565,6 @@ def fan(
|
|
553
565
|
raise ValueError(f"Invalid mode {mode}")
|
554
566
|
|
555
567
|
|
556
|
-
if __name__ == "__main__":
|
557
|
-
|
558
|
-
|
568
|
+
# if __name__ == "__main__":
|
569
|
+
# # This is only for perf testing purposes.
|
570
|
+
# prepare_configurations(run_id="abc", pipeline_file="examples/mocking.yaml")
|
runnable/exceptions.py
CHANGED
@@ -10,6 +10,18 @@ class RunLogExistsError(Exception): # pragma: no cover
|
|
10
10
|
self.message = f"Run id for {run_id} is already found in the datastore"
|
11
11
|
|
12
12
|
|
13
|
+
class JobLogNotFoundError(Exception):
|
14
|
+
"""
|
15
|
+
Exception class
|
16
|
+
Args:
|
17
|
+
Exception ([type]): [description]
|
18
|
+
"""
|
19
|
+
|
20
|
+
def __init__(self, run_id):
|
21
|
+
super().__init__()
|
22
|
+
self.message = f"Job for {run_id} is not found in the datastore"
|
23
|
+
|
24
|
+
|
13
25
|
class RunLogNotFoundError(Exception): # pragma: no cover
|
14
26
|
"""
|
15
27
|
Exception class
|
@@ -74,6 +86,16 @@ class BranchNotFoundError(Exception): # pragma: no cover
|
|
74
86
|
self.message = f"Branch of name {name} is not found the graph"
|
75
87
|
|
76
88
|
|
89
|
+
class NodeMethodCallError(Exception):
|
90
|
+
"""
|
91
|
+
Exception class
|
92
|
+
"""
|
93
|
+
|
94
|
+
def __init__(self, message):
|
95
|
+
super().__init__()
|
96
|
+
self.message = message
|
97
|
+
|
98
|
+
|
77
99
|
class TerminalNodeError(Exception): # pragma: no cover
|
78
100
|
def __init__(self):
|
79
101
|
super().__init__()
|