ddeutil-workflow 0.0.50__py3-none-any.whl → 0.0.51__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.
- ddeutil/workflow/__about__.py +1 -1
- ddeutil/workflow/__init__.py +4 -26
- ddeutil/workflow/conf.py +2 -2
- ddeutil/workflow/cron.py +46 -20
- ddeutil/workflow/job.py +166 -93
- ddeutil/workflow/logs.py +22 -18
- ddeutil/workflow/params.py +56 -16
- ddeutil/workflow/reusables.py +4 -2
- ddeutil/workflow/scheduler.py +5 -1
- ddeutil/workflow/stages.py +309 -146
- ddeutil/workflow/workflow.py +76 -72
- {ddeutil_workflow-0.0.50.dist-info → ddeutil_workflow-0.0.51.dist-info}/METADATA +69 -13
- {ddeutil_workflow-0.0.50.dist-info → ddeutil_workflow-0.0.51.dist-info}/RECORD +16 -16
- {ddeutil_workflow-0.0.50.dist-info → ddeutil_workflow-0.0.51.dist-info}/WHEEL +0 -0
- {ddeutil_workflow-0.0.50.dist-info → ddeutil_workflow-0.0.51.dist-info}/licenses/LICENSE +0 -0
- {ddeutil_workflow-0.0.50.dist-info → ddeutil_workflow-0.0.51.dist-info}/top_level.txt +0 -0
ddeutil/workflow/job.py
CHANGED
@@ -27,18 +27,18 @@ from threading import Event
|
|
27
27
|
from typing import Annotated, Any, Literal, Optional, Union
|
28
28
|
|
29
29
|
from ddeutil.core import freeze_args
|
30
|
-
from pydantic import BaseModel, ConfigDict, Discriminator, Field, Tag
|
30
|
+
from pydantic import BaseModel, ConfigDict, Discriminator, Field, SecretStr, Tag
|
31
31
|
from pydantic.functional_validators import field_validator, model_validator
|
32
32
|
from typing_extensions import Self
|
33
33
|
|
34
|
-
from .__types import DictData, DictStr, Matrix
|
34
|
+
from .__types import DictData, DictStr, Matrix
|
35
35
|
from .exceptions import (
|
36
36
|
JobException,
|
37
37
|
StageException,
|
38
38
|
UtilException,
|
39
39
|
to_dict,
|
40
40
|
)
|
41
|
-
from .result import FAILED, SKIP, SUCCESS, WAIT, Result, Status
|
41
|
+
from .result import CANCEL, FAILED, SKIP, SUCCESS, WAIT, Result, Status
|
42
42
|
from .reusables import has_template, param2template
|
43
43
|
from .stages import Stage
|
44
44
|
from .utils import cross_product, filter_func, gen_id
|
@@ -46,21 +46,6 @@ from .utils import cross_product, filter_func, gen_id
|
|
46
46
|
MatrixFilter = list[dict[str, Union[str, int]]]
|
47
47
|
|
48
48
|
|
49
|
-
__all__: TupleStr = (
|
50
|
-
"Strategy",
|
51
|
-
"Job",
|
52
|
-
"Rule",
|
53
|
-
"RunsOn",
|
54
|
-
"RunsOnModel",
|
55
|
-
"OnLocal",
|
56
|
-
"OnSelfHosted",
|
57
|
-
"OnK8s",
|
58
|
-
"make",
|
59
|
-
"local_execute_strategy",
|
60
|
-
"local_execute",
|
61
|
-
)
|
62
|
-
|
63
|
-
|
64
49
|
@freeze_args
|
65
50
|
@lru_cache
|
66
51
|
def make(
|
@@ -120,7 +105,6 @@ def make(
|
|
120
105
|
|
121
106
|
add.append(inc)
|
122
107
|
|
123
|
-
# NOTE: Merge all matrix together.
|
124
108
|
final.extend(add)
|
125
109
|
return final
|
126
110
|
|
@@ -210,8 +194,8 @@ class RunsOn(str, Enum):
|
|
210
194
|
|
211
195
|
LOCAL: str = "local"
|
212
196
|
SELF_HOSTED: str = "self_hosted"
|
213
|
-
K8S: str = "k8s"
|
214
197
|
AZ_BATCH: str = "azure_batch"
|
198
|
+
DOCKER: str = "docker"
|
215
199
|
|
216
200
|
|
217
201
|
class BaseRunsOn(BaseModel): # pragma: no cov
|
@@ -221,10 +205,14 @@ class BaseRunsOn(BaseModel): # pragma: no cov
|
|
221
205
|
|
222
206
|
model_config = ConfigDict(use_enum_values=True)
|
223
207
|
|
224
|
-
type:
|
208
|
+
type: RunsOn = Field(description="A runs-on type.")
|
225
209
|
args: DictData = Field(
|
226
210
|
default_factory=dict,
|
227
211
|
alias="with",
|
212
|
+
description=(
|
213
|
+
"An argument that pass to the runs-on execution function. This "
|
214
|
+
"args will override by this child-model with specific args model."
|
215
|
+
),
|
228
216
|
)
|
229
217
|
|
230
218
|
|
@@ -235,7 +223,9 @@ class OnLocal(BaseRunsOn): # pragma: no cov
|
|
235
223
|
|
236
224
|
|
237
225
|
class SelfHostedArgs(BaseModel):
|
238
|
-
|
226
|
+
"""Self-Hosted arguments."""
|
227
|
+
|
228
|
+
host: str = Field(description="A host URL of the target self-hosted.")
|
239
229
|
|
240
230
|
|
241
231
|
class OnSelfHosted(BaseRunsOn): # pragma: no cov
|
@@ -245,20 +235,48 @@ class OnSelfHosted(BaseRunsOn): # pragma: no cov
|
|
245
235
|
args: SelfHostedArgs = Field(alias="with")
|
246
236
|
|
247
237
|
|
248
|
-
class
|
249
|
-
|
238
|
+
class AzBatchArgs(BaseModel):
|
239
|
+
batch_account_name: str
|
240
|
+
batch_account_key: SecretStr
|
241
|
+
batch_account_url: str
|
242
|
+
storage_account_name: str
|
243
|
+
storage_account_key: SecretStr
|
244
|
+
|
245
|
+
|
246
|
+
class OnAzBatch(BaseRunsOn): # pragma: no cov
|
247
|
+
|
248
|
+
type: Literal[RunsOn.AZ_BATCH] = Field(default=RunsOn.AZ_BATCH)
|
249
|
+
args: AzBatchArgs = Field(alias="with")
|
250
|
+
|
251
|
+
|
252
|
+
class DockerArgs(BaseModel):
|
253
|
+
image: str = Field(
|
254
|
+
default="ubuntu-latest",
|
255
|
+
description=(
|
256
|
+
"An image that want to run like `ubuntu-22.04`, `windows-latest`, "
|
257
|
+
", `ubuntu-24.04-arm`, or `macos-14`"
|
258
|
+
),
|
259
|
+
)
|
260
|
+
env: DictData = Field(default_factory=dict)
|
261
|
+
volume: DictData = Field(default_factory=dict)
|
262
|
+
|
250
263
|
|
251
|
-
|
264
|
+
class OnDocker(BaseRunsOn): # pragma: no cov
|
265
|
+
"""Runs-on Docker container."""
|
266
|
+
|
267
|
+
type: Literal[RunsOn.DOCKER] = Field(default=RunsOn.DOCKER)
|
268
|
+
args: DockerArgs = Field(alias="with", default_factory=DockerArgs)
|
252
269
|
|
253
270
|
|
254
271
|
def get_discriminator_runs_on(model: dict[str, Any]) -> str:
|
272
|
+
"""Get discriminator of the RunsOn models."""
|
255
273
|
return model.get("type", "local")
|
256
274
|
|
257
275
|
|
258
276
|
RunsOnModel = Annotated[
|
259
277
|
Union[
|
260
|
-
Annotated[OnK8s, Tag(RunsOn.K8S)],
|
261
278
|
Annotated[OnSelfHosted, Tag(RunsOn.SELF_HOSTED)],
|
279
|
+
Annotated[OnDocker, Tag(RunsOn.DOCKER)],
|
262
280
|
Annotated[OnLocal, Tag(RunsOn.LOCAL)],
|
263
281
|
],
|
264
282
|
Discriminator(get_discriminator_runs_on),
|
@@ -288,7 +306,6 @@ class Job(BaseModel):
|
|
288
306
|
... "name": "Some stage",
|
289
307
|
... "run": "print('Hello World')",
|
290
308
|
... },
|
291
|
-
... ...
|
292
309
|
... ],
|
293
310
|
... }
|
294
311
|
"""
|
@@ -327,7 +344,7 @@ class Job(BaseModel):
|
|
327
344
|
)
|
328
345
|
needs: list[str] = Field(
|
329
346
|
default_factory=list,
|
330
|
-
description="A list of the job
|
347
|
+
description="A list of the job that want to run before this job model.",
|
331
348
|
)
|
332
349
|
strategy: Strategy = Field(
|
333
350
|
default_factory=Strategy,
|
@@ -359,7 +376,7 @@ class Job(BaseModel):
|
|
359
376
|
name: str = stage.iden
|
360
377
|
if name in rs:
|
361
378
|
raise ValueError(
|
362
|
-
"Stage name
|
379
|
+
f"Stage name, {name!r}, should not be duplicate."
|
363
380
|
)
|
364
381
|
rs.append(name)
|
365
382
|
return value
|
@@ -372,7 +389,9 @@ class Job(BaseModel):
|
|
372
389
|
"""
|
373
390
|
# VALIDATE: Validate job id should not dynamic with params template.
|
374
391
|
if has_template(self.id):
|
375
|
-
raise ValueError(
|
392
|
+
raise ValueError(
|
393
|
+
f"Job ID, {self.id!r}, should not has any template."
|
394
|
+
)
|
376
395
|
|
377
396
|
return self
|
378
397
|
|
@@ -390,7 +409,7 @@ class Job(BaseModel):
|
|
390
409
|
if self.extras:
|
391
410
|
stage.extras = self.extras
|
392
411
|
return stage
|
393
|
-
raise ValueError(f"Stage
|
412
|
+
raise ValueError(f"Stage {stage_id!r} does not exists in this job.")
|
394
413
|
|
395
414
|
def check_needs(
|
396
415
|
self,
|
@@ -497,14 +516,14 @@ class Job(BaseModel):
|
|
497
516
|
... (i) output: {'strategy-01': bar, 'strategy-02': bar}
|
498
517
|
... (ii) to: {'jobs': {}}
|
499
518
|
|
500
|
-
The result of the `to`
|
519
|
+
The result of the `to` argument will be;
|
501
520
|
|
502
521
|
... (iii) to: {
|
503
522
|
'jobs': {
|
504
523
|
'<job-id>': {
|
505
524
|
'strategies': {
|
506
525
|
'strategy-01': bar,
|
507
|
-
'strategy-02': bar
|
526
|
+
'strategy-02': bar,
|
508
527
|
}
|
509
528
|
}
|
510
529
|
}
|
@@ -527,22 +546,27 @@ class Job(BaseModel):
|
|
527
546
|
"This job do not set the ID before setting execution output."
|
528
547
|
)
|
529
548
|
|
530
|
-
# NOTE: If the job ID did not set, it will use index of jobs key
|
531
|
-
# instead.
|
532
549
|
_id: str = self.id or job_id
|
533
|
-
|
534
550
|
errors: DictData = (
|
535
551
|
{"errors": output.pop("errors", {})} if "errors" in output else {}
|
536
552
|
)
|
553
|
+
skipping: dict[str, bool] = (
|
554
|
+
{"skipped": output.pop("skipped", False)}
|
555
|
+
if "skipped" in output
|
556
|
+
else {}
|
557
|
+
)
|
537
558
|
|
538
|
-
if
|
539
|
-
to["jobs"][_id] =
|
540
|
-
elif
|
541
|
-
|
559
|
+
if self.strategy.is_set():
|
560
|
+
to["jobs"][_id] = {"strategies": output, **skipping, **errors}
|
561
|
+
elif len(k := output.keys()) > 1: # pragma: no cov
|
562
|
+
raise JobException(
|
563
|
+
"Strategy output from execution return more than one ID while "
|
564
|
+
"this job does not set strategy."
|
565
|
+
)
|
542
566
|
else:
|
543
|
-
_output =
|
567
|
+
_output: DictData = {} if len(k) == 0 else output[list(k)[0]]
|
544
568
|
_output.pop("matrix", {})
|
545
|
-
to["jobs"][_id] = {**_output, **errors}
|
569
|
+
to["jobs"][_id] = {**_output, **skipping, **errors}
|
546
570
|
return to
|
547
571
|
|
548
572
|
def execute(
|
@@ -559,6 +583,9 @@ class Job(BaseModel):
|
|
559
583
|
execution. It will generate matrix values at the first step and run
|
560
584
|
multithread on this metrics to the `stages` field of this job.
|
561
585
|
|
586
|
+
This method be execution routing for call dynamic execution function
|
587
|
+
with specific target `runs-on` value.
|
588
|
+
|
562
589
|
:param params: An input parameters that use on job execution.
|
563
590
|
:param run_id: (str) A job running ID.
|
564
591
|
:param parent_run_id: (str) A parent workflow running ID.
|
@@ -566,8 +593,10 @@ class Job(BaseModel):
|
|
566
593
|
data.
|
567
594
|
:param event: (Event) An event manager that pass to the
|
568
595
|
PoolThreadExecutor.
|
569
|
-
:param raise_error: (bool) A flag that all this method raise error to
|
570
|
-
strategy execution. Default is `True`.
|
596
|
+
:param raise_error: (bool) A flag that all this method raise error to
|
597
|
+
the strategy execution. Default is `True`.
|
598
|
+
|
599
|
+
:raise NotImplementedError: If the `runs-on` value does not implement.
|
571
600
|
|
572
601
|
:rtype: Result
|
573
602
|
"""
|
@@ -579,28 +608,36 @@ class Job(BaseModel):
|
|
579
608
|
extras=self.extras,
|
580
609
|
)
|
581
610
|
|
582
|
-
result.trace.info(
|
611
|
+
result.trace.info(
|
612
|
+
f"[JOB]: Execute: {self.id!r} on {self.runs_on.type!r}"
|
613
|
+
)
|
583
614
|
if self.runs_on.type == RunsOn.LOCAL:
|
584
615
|
return local_execute(
|
585
|
-
|
586
|
-
params
|
587
|
-
|
616
|
+
self,
|
617
|
+
params,
|
618
|
+
run_id=run_id,
|
619
|
+
parent_run_id=parent_run_id,
|
588
620
|
event=event,
|
589
621
|
raise_error=raise_error,
|
590
622
|
)
|
591
623
|
elif self.runs_on.type == RunsOn.SELF_HOSTED: # pragma: no cov
|
592
624
|
pass
|
593
|
-
elif self.runs_on.type == RunsOn.
|
594
|
-
|
625
|
+
elif self.runs_on.type == RunsOn.DOCKER: # pragma: no cov
|
626
|
+
docker_execution(
|
627
|
+
self,
|
628
|
+
params,
|
629
|
+
run_id=run_id,
|
630
|
+
parent_run_id=parent_run_id,
|
631
|
+
event=event,
|
632
|
+
raise_error=raise_error,
|
633
|
+
)
|
595
634
|
|
596
635
|
# pragma: no cov
|
597
636
|
result.trace.error(
|
598
|
-
f"[JOB]:
|
599
|
-
f"{self.runs_on.type} yet"
|
637
|
+
f"[JOB]: Execution not support runs-on: {self.runs_on.type!r} yet."
|
600
638
|
)
|
601
639
|
raise NotImplementedError(
|
602
|
-
f"
|
603
|
-
f"support yet."
|
640
|
+
f"Execution runs-on type: {self.runs_on.type} does not support yet."
|
604
641
|
)
|
605
642
|
|
606
643
|
|
@@ -622,6 +659,8 @@ def local_execute_strategy(
|
|
622
659
|
|
623
660
|
The result of this execution will return result with strategy ID
|
624
661
|
that generated from the `gen_id` function with an input strategy value.
|
662
|
+
For each stage that execution with this strategy metrix, it will use the
|
663
|
+
`set_outputs` method for reconstruct result context data.
|
625
664
|
|
626
665
|
:raise JobException: If it has any error from `StageException` or
|
627
666
|
`UtilException`.
|
@@ -645,8 +684,10 @@ def local_execute_strategy(
|
|
645
684
|
context.update({"matrix": strategy, "stages": {}})
|
646
685
|
|
647
686
|
if strategy:
|
648
|
-
result.trace.info(f"[JOB]: Execute Strategy
|
649
|
-
result.trace.info(f"[JOB]: ...
|
687
|
+
result.trace.info(f"[JOB]: Execute Strategy: {strategy_id!r}")
|
688
|
+
result.trace.info(f"[JOB]: ... matrix: {strategy!r}")
|
689
|
+
else:
|
690
|
+
result.trace.info("[JOB]: Execute Empty-Strategy")
|
650
691
|
|
651
692
|
for stage in job.stages:
|
652
693
|
|
@@ -654,7 +695,7 @@ def local_execute_strategy(
|
|
654
695
|
stage.extras = job.extras
|
655
696
|
|
656
697
|
if stage.is_skipped(params=context):
|
657
|
-
result.trace.info(f"[
|
698
|
+
result.trace.info(f"[JOB]: Skip Stage: {stage.iden!r}")
|
658
699
|
stage.set_outputs(output={"skipped": True}, to=context)
|
659
700
|
continue
|
660
701
|
|
@@ -664,7 +705,7 @@ def local_execute_strategy(
|
|
664
705
|
"strategy execution."
|
665
706
|
)
|
666
707
|
return result.catch(
|
667
|
-
status=
|
708
|
+
status=CANCEL,
|
668
709
|
context={
|
669
710
|
strategy_id: {
|
670
711
|
"matrix": strategy,
|
@@ -675,6 +716,7 @@ def local_execute_strategy(
|
|
675
716
|
)
|
676
717
|
|
677
718
|
try:
|
719
|
+
result.trace.info(f"[JOB]: Execute Stage: {stage.iden!r}")
|
678
720
|
rs: Result = stage.handler_execute(
|
679
721
|
params=context,
|
680
722
|
run_id=result.run_id,
|
@@ -682,22 +724,6 @@ def local_execute_strategy(
|
|
682
724
|
event=event,
|
683
725
|
)
|
684
726
|
stage.set_outputs(rs.context, to=context)
|
685
|
-
if rs.status == FAILED:
|
686
|
-
error_msg: str = (
|
687
|
-
f"Job strategy was break because it has a stage, "
|
688
|
-
f"{stage.iden}, failed without raise error."
|
689
|
-
)
|
690
|
-
return result.catch(
|
691
|
-
status=FAILED,
|
692
|
-
context={
|
693
|
-
strategy_id: {
|
694
|
-
"matrix": strategy,
|
695
|
-
"stages": filter_func(context.pop("stages", {})),
|
696
|
-
"errors": JobException(error_msg).to_dict(),
|
697
|
-
},
|
698
|
-
},
|
699
|
-
)
|
700
|
-
|
701
727
|
except (StageException, UtilException) as e:
|
702
728
|
result.trace.error(f"[JOB]: {e.__class__.__name__}: {e}")
|
703
729
|
if raise_error:
|
@@ -716,6 +742,22 @@ def local_execute_strategy(
|
|
716
742
|
},
|
717
743
|
)
|
718
744
|
|
745
|
+
if rs.status == FAILED:
|
746
|
+
error_msg: str = (
|
747
|
+
f"Job strategy was break because stage, {stage.iden}, "
|
748
|
+
f"failed without raise error."
|
749
|
+
)
|
750
|
+
return result.catch(
|
751
|
+
status=FAILED,
|
752
|
+
context={
|
753
|
+
strategy_id: {
|
754
|
+
"matrix": strategy,
|
755
|
+
"stages": filter_func(context.pop("stages", {})),
|
756
|
+
"errors": JobException(error_msg).to_dict(),
|
757
|
+
},
|
758
|
+
},
|
759
|
+
)
|
760
|
+
|
719
761
|
return result.catch(
|
720
762
|
status=SUCCESS,
|
721
763
|
context={
|
@@ -733,7 +775,6 @@ def local_execute(
|
|
733
775
|
*,
|
734
776
|
run_id: str | None = None,
|
735
777
|
parent_run_id: str | None = None,
|
736
|
-
result: Result | None = None,
|
737
778
|
event: Event | None = None,
|
738
779
|
raise_error: bool = True,
|
739
780
|
) -> Result:
|
@@ -748,8 +789,6 @@ def local_execute(
|
|
748
789
|
:param params: (DictData) An input parameters that use on job execution.
|
749
790
|
:param run_id: (str) A job running ID for this execution.
|
750
791
|
:param parent_run_id: (str) A parent workflow running ID for this release.
|
751
|
-
:param result: (Result) A result object for keeping context and status
|
752
|
-
data.
|
753
792
|
:param event: (Event) An event manager that pass to the PoolThreadExecutor.
|
754
793
|
:param raise_error: (bool) A flag that all this method raise error to the
|
755
794
|
strategy execution. Default is `True`.
|
@@ -757,12 +796,12 @@ def local_execute(
|
|
757
796
|
:rtype: Result
|
758
797
|
"""
|
759
798
|
result: Result = Result.construct_with_rs_or_id(
|
760
|
-
result,
|
761
799
|
run_id=run_id,
|
762
800
|
parent_run_id=parent_run_id,
|
763
801
|
id_logic=(job.id or "not-set"),
|
764
802
|
extras=job.extras,
|
765
803
|
)
|
804
|
+
|
766
805
|
event: Event = Event() if event is None else event
|
767
806
|
|
768
807
|
# NOTE: Normal Job execution without parallel strategy matrix. It uses
|
@@ -773,7 +812,7 @@ def local_execute(
|
|
773
812
|
|
774
813
|
if event and event.is_set(): # pragma: no cov
|
775
814
|
return result.catch(
|
776
|
-
status=
|
815
|
+
status=CANCEL,
|
777
816
|
context={
|
778
817
|
"errors": JobException(
|
779
818
|
"Job strategy was canceled from event that had set "
|
@@ -791,7 +830,7 @@ def local_execute(
|
|
791
830
|
raise_error=raise_error,
|
792
831
|
)
|
793
832
|
|
794
|
-
return result
|
833
|
+
return result
|
795
834
|
|
796
835
|
fail_fast_flag: bool = job.strategy.fail_fast
|
797
836
|
ls: str = "Fail-Fast" if fail_fast_flag else "All-Completed"
|
@@ -802,7 +841,7 @@ def local_execute(
|
|
802
841
|
|
803
842
|
if event and event.is_set(): # pragma: no cov
|
804
843
|
return result.catch(
|
805
|
-
status=
|
844
|
+
status=CANCEL,
|
806
845
|
context={
|
807
846
|
"errors": JobException(
|
808
847
|
"Job strategy was canceled from event that had set "
|
@@ -841,7 +880,7 @@ def local_execute(
|
|
841
880
|
|
842
881
|
if len(done) != len(futures):
|
843
882
|
result.trace.warning(
|
844
|
-
"[JOB]: Set
|
883
|
+
"[JOB]: Set event for stop pending stage future."
|
845
884
|
)
|
846
885
|
event.set()
|
847
886
|
for future in not_done:
|
@@ -850,7 +889,7 @@ def local_execute(
|
|
850
889
|
nd: str = (
|
851
890
|
f", the strategies do not run is {not_done}" if not_done else ""
|
852
891
|
)
|
853
|
-
result.trace.debug(f"[JOB]: Strategy
|
892
|
+
result.trace.debug(f"[JOB]: Strategy set Fail-Fast{nd}")
|
854
893
|
|
855
894
|
for future in done:
|
856
895
|
try:
|
@@ -871,7 +910,6 @@ def self_hosted_execute(
|
|
871
910
|
*,
|
872
911
|
run_id: str | None = None,
|
873
912
|
parent_run_id: str | None = None,
|
874
|
-
result: Result | None = None,
|
875
913
|
event: Event | None = None,
|
876
914
|
raise_error: bool = True,
|
877
915
|
) -> Result: # pragma: no cov
|
@@ -883,8 +921,6 @@ def self_hosted_execute(
|
|
883
921
|
:param params: (DictData) An input parameters that use on job execution.
|
884
922
|
:param run_id: (str) A job running ID for this execution.
|
885
923
|
:param parent_run_id: (str) A parent workflow running ID for this release.
|
886
|
-
:param result: (Result) A result object for keeping context and status
|
887
|
-
data.
|
888
924
|
:param event: (Event) An event manager that pass to the PoolThreadExecutor.
|
889
925
|
:param raise_error: (bool) A flag that all this method raise error to the
|
890
926
|
strategy execution.
|
@@ -892,7 +928,6 @@ def self_hosted_execute(
|
|
892
928
|
:rtype: Result
|
893
929
|
"""
|
894
930
|
result: Result = Result.construct_with_rs_or_id(
|
895
|
-
result,
|
896
931
|
run_id=run_id,
|
897
932
|
parent_run_id=parent_run_id,
|
898
933
|
id_logic=(job.id or "not-set"),
|
@@ -901,7 +936,7 @@ def self_hosted_execute(
|
|
901
936
|
|
902
937
|
if event and event.is_set():
|
903
938
|
return result.catch(
|
904
|
-
status=
|
939
|
+
status=CANCEL,
|
905
940
|
context={
|
906
941
|
"errors": JobException(
|
907
942
|
"Job self-hosted execution was canceled from event that "
|
@@ -943,7 +978,6 @@ def azure_batch_execute(
|
|
943
978
|
*,
|
944
979
|
run_id: str | None = None,
|
945
980
|
parent_run_id: str | None = None,
|
946
|
-
result: Result | None = None,
|
947
981
|
event: Event | None = None,
|
948
982
|
raise_error: bool | None = None,
|
949
983
|
) -> Result: # pragma no cov
|
@@ -962,17 +996,19 @@ def azure_batch_execute(
|
|
962
996
|
the compute node before running the script.
|
963
997
|
- Monitor the job and retrieve the output files from Azure Storage.
|
964
998
|
|
999
|
+
References:
|
1000
|
+
- https://docs.azure.cn/en-us/batch/tutorial-parallel-python
|
1001
|
+
|
965
1002
|
:param job:
|
966
1003
|
:param params:
|
967
1004
|
:param run_id:
|
968
1005
|
:param parent_run_id:
|
969
|
-
:param result:
|
970
1006
|
:param event:
|
971
1007
|
:param raise_error:
|
972
|
-
|
1008
|
+
|
1009
|
+
:rtype: Result
|
973
1010
|
"""
|
974
1011
|
result: Result = Result.construct_with_rs_or_id(
|
975
|
-
result,
|
976
1012
|
run_id=run_id,
|
977
1013
|
parent_run_id=parent_run_id,
|
978
1014
|
id_logic=(job.id or "not-set"),
|
@@ -980,7 +1016,7 @@ def azure_batch_execute(
|
|
980
1016
|
)
|
981
1017
|
if event and event.is_set():
|
982
1018
|
return result.catch(
|
983
|
-
status=
|
1019
|
+
status=CANCEL,
|
984
1020
|
context={
|
985
1021
|
"errors": JobException(
|
986
1022
|
"Job azure-batch execution was canceled from event that "
|
@@ -991,3 +1027,40 @@ def azure_batch_execute(
|
|
991
1027
|
print(params)
|
992
1028
|
print(raise_error)
|
993
1029
|
return result.catch(status=SUCCESS)
|
1030
|
+
|
1031
|
+
|
1032
|
+
def docker_execution(
|
1033
|
+
job: Job,
|
1034
|
+
params: DictData,
|
1035
|
+
*,
|
1036
|
+
run_id: str | None = None,
|
1037
|
+
parent_run_id: str | None = None,
|
1038
|
+
event: Event | None = None,
|
1039
|
+
raise_error: bool | None = None,
|
1040
|
+
):
|
1041
|
+
"""Docker job execution.
|
1042
|
+
|
1043
|
+
Steps:
|
1044
|
+
- Pull the image
|
1045
|
+
- Install this workflow package
|
1046
|
+
- Start push job to run to target Docker container.
|
1047
|
+
"""
|
1048
|
+
result: Result = Result.construct_with_rs_or_id(
|
1049
|
+
run_id=run_id,
|
1050
|
+
parent_run_id=parent_run_id,
|
1051
|
+
id_logic=(job.id or "not-set"),
|
1052
|
+
extras=job.extras,
|
1053
|
+
)
|
1054
|
+
if event and event.is_set():
|
1055
|
+
return result.catch(
|
1056
|
+
status=CANCEL,
|
1057
|
+
context={
|
1058
|
+
"errors": JobException(
|
1059
|
+
"Job Docker execution was canceled from event that "
|
1060
|
+
"had set before start execution."
|
1061
|
+
).to_dict()
|
1062
|
+
},
|
1063
|
+
)
|
1064
|
+
print(params)
|
1065
|
+
print(raise_error)
|
1066
|
+
return result.catch(status=SUCCESS)
|
ddeutil/workflow/logs.py
CHANGED
@@ -224,18 +224,30 @@ class BaseTrace(ABC): # pragma: no cov
|
|
224
224
|
"Adjust make message method for this trace object before using."
|
225
225
|
)
|
226
226
|
|
227
|
-
def
|
228
|
-
|
229
|
-
|
227
|
+
def __logging(
|
228
|
+
self, message: str, mode: str, *, is_err: bool = False
|
229
|
+
) -> None:
|
230
|
+
"""Write trace log with append mode and logging this message with any
|
231
|
+
logging level.
|
230
232
|
|
231
233
|
:param message: (str) A message that want to log.
|
232
234
|
"""
|
233
235
|
msg: str = self.make_message(message)
|
234
236
|
|
235
|
-
if
|
236
|
-
self.
|
237
|
+
if mode != "debug" or (
|
238
|
+
mode == "debug" and dynamic("debug", extras=self.extras)
|
239
|
+
):
|
240
|
+
self.writer(msg, is_err=is_err)
|
241
|
+
|
242
|
+
getattr(logger, mode)(msg, stacklevel=3)
|
243
|
+
|
244
|
+
def debug(self, message: str):
|
245
|
+
"""Write trace log with append mode and logging this message with the
|
246
|
+
DEBUG level.
|
237
247
|
|
238
|
-
|
248
|
+
:param message: (str) A message that want to log.
|
249
|
+
"""
|
250
|
+
self.__logging(message, mode="debug")
|
239
251
|
|
240
252
|
def info(self, message: str) -> None:
|
241
253
|
"""Write trace log with append mode and logging this message with the
|
@@ -243,9 +255,7 @@ class BaseTrace(ABC): # pragma: no cov
|
|
243
255
|
|
244
256
|
:param message: (str) A message that want to log.
|
245
257
|
"""
|
246
|
-
|
247
|
-
self.writer(msg)
|
248
|
-
logger.info(msg, stacklevel=2)
|
258
|
+
self.__logging(message, mode="info")
|
249
259
|
|
250
260
|
def warning(self, message: str) -> None:
|
251
261
|
"""Write trace log with append mode and logging this message with the
|
@@ -253,9 +263,7 @@ class BaseTrace(ABC): # pragma: no cov
|
|
253
263
|
|
254
264
|
:param message: (str) A message that want to log.
|
255
265
|
"""
|
256
|
-
|
257
|
-
self.writer(msg)
|
258
|
-
logger.warning(msg, stacklevel=2)
|
266
|
+
self.__logging(message, mode="warning")
|
259
267
|
|
260
268
|
def error(self, message: str) -> None:
|
261
269
|
"""Write trace log with append mode and logging this message with the
|
@@ -263,9 +271,7 @@ class BaseTrace(ABC): # pragma: no cov
|
|
263
271
|
|
264
272
|
:param message: (str) A message that want to log.
|
265
273
|
"""
|
266
|
-
|
267
|
-
self.writer(msg, is_err=True)
|
268
|
-
logger.error(msg, stacklevel=2)
|
274
|
+
self.__logging(message, mode="error", is_err=True)
|
269
275
|
|
270
276
|
def exception(self, message: str) -> None:
|
271
277
|
"""Write trace log with append mode and logging this message with the
|
@@ -273,9 +279,7 @@ class BaseTrace(ABC): # pragma: no cov
|
|
273
279
|
|
274
280
|
:param message: (str) A message that want to log.
|
275
281
|
"""
|
276
|
-
|
277
|
-
self.writer(msg, is_err=True)
|
278
|
-
logger.exception(msg, stacklevel=2)
|
282
|
+
self.__logging(message, mode="exception", is_err=True)
|
279
283
|
|
280
284
|
async def adebug(self, message: str) -> None: # pragma: no cov
|
281
285
|
"""Async write trace log with append mode and logging this message with
|