ddeutil-workflow 0.0.53__py3-none-any.whl → 0.0.55__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/job.py CHANGED
@@ -3,12 +3,17 @@
3
3
  # Licensed under the MIT License. See LICENSE in the project root for
4
4
  # license information.
5
5
  # ------------------------------------------------------------------------------
6
- """Job Model that use for keeping stages and node that running its stages.
7
- The job handle the lineage of stages and location of execution of stages that
8
- mean the job model able to define `runs-on` key that allow you to run this
9
- job.
6
+ """Job model that use for store Stage models and node parameter that use for
7
+ running these stages. The job model handle the lineage of stages and location of
8
+ execution that mean you can define `runs-on` field with the Self-Hosted mode
9
+ for execute on target machine instead of the current local machine.
10
10
 
11
- This module include Strategy Model that use on the job strategy field.
11
+ This module include Strategy model that use on the job `strategy` field for
12
+ making matrix values before execution parallelism stage execution.
13
+
14
+ The Job model does not implement `handler_execute` same as Stage model
15
+ because the job should raise only `JobException` class from the execution
16
+ method.
12
17
  """
13
18
  from __future__ import annotations
14
19
 
@@ -41,7 +46,7 @@ from .exceptions import (
41
46
  from .result import CANCEL, FAILED, SKIP, SUCCESS, WAIT, Result, Status
42
47
  from .reusables import has_template, param2template
43
48
  from .stages import Stage
44
- from .utils import cross_product, filter_func, gen_id
49
+ from .utils import NEWLINE, cross_product, filter_func, gen_id
45
50
 
46
51
  MatrixFilter = list[dict[str, Union[str, int]]]
47
52
 
@@ -59,10 +64,10 @@ def make(
59
64
  This function use the `lru_cache` decorator function increase
60
65
  performance for duplicate matrix value scenario.
61
66
 
62
- :param matrix: A matrix values that want to cross product to possible
63
- parallelism values.
64
- :param include: A list of additional matrix that want to adds-in.
65
- :param exclude: A list of exclude matrix that want to filter-out.
67
+ :param matrix: (Matrix) A matrix values that want to cross product to
68
+ possible parallelism values.
69
+ :param include: (A list of additional matrix that want to adds-in.
70
+ :param exclude: (A list of exclude matrix that want to filter-out.
66
71
 
67
72
  :rtype: list[DictStr]
68
73
  """
@@ -320,12 +325,13 @@ class Job(BaseModel):
320
325
  id: Optional[str] = Field(
321
326
  default=None,
322
327
  description=(
323
- "A job ID that it will add from workflow after validation process."
328
+ "A job ID that was set from Workflow model after initialize step. "
329
+ "If this model create standalone, it will be None."
324
330
  ),
325
331
  )
326
332
  desc: Optional[str] = Field(
327
333
  default=None,
328
- description="A job description that can be string of markdown content.",
334
+ description="A job description that can be markdown syntax.",
329
335
  )
330
336
  runs_on: RunsOnModel = Field(
331
337
  default_factory=OnLocal,
@@ -339,7 +345,7 @@ class Job(BaseModel):
339
345
  )
340
346
  stages: list[Stage] = Field(
341
347
  default_factory=list,
342
- description="A list of Stage of this job.",
348
+ description="A list of Stage model of this job.",
343
349
  )
344
350
  trigger_rule: Rule = Field(
345
351
  default=Rule.ALL_SUCCESS,
@@ -373,7 +379,7 @@ class Job(BaseModel):
373
379
 
374
380
  @field_validator("stages", mode="after")
375
381
  def __validate_stage_id__(cls, value: list[Stage]) -> list[Stage]:
376
- """Validate a stage ID of all stage in stages field should not be
382
+ """Validate stage ID of each stage in the `stages` field should not be
377
383
  duplicate.
378
384
 
379
385
  :rtype: list[Stage]
@@ -391,11 +397,10 @@ class Job(BaseModel):
391
397
 
392
398
  @model_validator(mode="after")
393
399
  def __validate_job_id__(self) -> Self:
394
- """Validate job id should not have templating syntax.
400
+ """Validate job id should not dynamic with params template.
395
401
 
396
402
  :rtype: Self
397
403
  """
398
- # VALIDATE: Validate job id should not dynamic with params template.
399
404
  if has_template(self.id):
400
405
  raise ValueError(
401
406
  f"Job ID, {self.id!r}, should not has any template."
@@ -419,14 +424,11 @@ class Job(BaseModel):
419
424
  return stage
420
425
  raise ValueError(f"Stage {stage_id!r} does not exists in this job.")
421
426
 
422
- def check_needs(
423
- self,
424
- jobs: dict[str, Any],
425
- ) -> Status: # pragma: no cov
426
- """Return Status enum for checking job's need trigger logic in an
427
- input list of job's ID.
427
+ def check_needs(self, jobs: dict[str, Any]) -> Status: # pragma: no cov
428
+ """Return trigger status from checking job's need trigger rule logic was
429
+ valid. The return status should be SUCCESS, FAILED, WAIT, or SKIP.
428
430
 
429
- :param jobs: A mapping of job ID and result context.
431
+ :param jobs: A mapping of job ID and its context data.
430
432
 
431
433
  :raise NotImplementedError: If the job trigger rule out of scope.
432
434
 
@@ -441,7 +443,6 @@ class Job(BaseModel):
441
443
  need_exist: dict[str, Any] = {
442
444
  need: jobs[need] for need in self.needs if need in jobs
443
445
  }
444
-
445
446
  if len(need_exist) != len(self.needs):
446
447
  return WAIT
447
448
  elif all("skipped" in need_exist[job] for job in need_exist):
@@ -469,30 +470,26 @@ class Job(BaseModel):
469
470
  elif self.trigger_rule == Rule.NONE_FAILED:
470
471
  rs = all("errors" not in need_exist[job] for job in need_exist)
471
472
  else: # pragma: no cov
472
- raise NotImplementedError(
473
- f"Trigger rule: {self.trigger_rule} does not support yet."
474
- )
473
+ return FAILED
475
474
  return make_return(rs)
476
475
 
477
- def is_skipped(self, params: DictData | None = None) -> bool:
476
+ def is_skipped(self, params: DictData) -> bool:
478
477
  """Return true if condition of this job do not correct. This process
479
478
  use build-in eval function to execute the if-condition.
480
479
 
480
+ :param params: (DictData) A parameter value that want to pass to condition
481
+ template.
482
+
481
483
  :raise JobException: When it has any error raise from the eval
482
484
  condition statement.
483
485
  :raise JobException: When return type of the eval condition statement
484
486
  does not return with boolean type.
485
487
 
486
- :param params: (DictData) A parameters that want to pass to condition
487
- template.
488
-
489
488
  :rtype: bool
490
489
  """
491
490
  if self.condition is None:
492
491
  return False
493
492
 
494
- params: DictData = {} if params is None else params
495
-
496
493
  try:
497
494
  # WARNING: The eval build-in function is very dangerous. So, it
498
495
  # should use the `re` module to validate eval-string before
@@ -513,15 +510,20 @@ class Job(BaseModel):
513
510
  output: DictData,
514
511
  to: DictData,
515
512
  *,
516
- job_id: Optional[None] = None,
513
+ job_id: Optional[str] = None,
517
514
  ) -> DictData:
518
- """Set an outputs from execution process to the received context. The
519
- result from execution will pass to value of `strategies` key.
515
+ """Set an outputs from execution result context to the received context
516
+ with a `to` input parameter. The result context from job strategy
517
+ execution will be set with `strategies` key in this job ID key.
520
518
 
521
519
  For example of setting output method, If you receive execute output
522
520
  and want to set on the `to` like;
523
521
 
524
- ... (i) output: {'strategy-01': bar, 'strategy-02': bar}
522
+ ... (i) output: {
523
+ 'strategy-01': 'foo',
524
+ 'strategy-02': 'bar',
525
+ 'skipped': True,
526
+ }
525
527
  ... (ii) to: {'jobs': {}}
526
528
 
527
529
  The result of the `to` argument will be;
@@ -530,19 +532,26 @@ class Job(BaseModel):
530
532
  'jobs': {
531
533
  '<job-id>': {
532
534
  'strategies': {
533
- 'strategy-01': bar,
534
- 'strategy-02': bar,
535
- }
535
+ 'strategy-01': 'foo',
536
+ 'strategy-02': 'bar',
537
+ },
538
+ 'skipped': True,
536
539
  }
537
540
  }
538
541
  }
539
542
 
543
+ The keys that will set to the received context is `strategies`,
544
+ `errors`, and `skipped` keys. The `errors` and `skipped` keys will
545
+ extract from the result context if it exists. If it does not found, it
546
+ will not set on the received context.
547
+
540
548
  :raise JobException: If the job's ID does not set and the setting
541
549
  default job ID flag does not set.
542
550
 
543
- :param output: An output context.
544
- :param to: A context data that want to add output result.
545
- :param job_id: A job ID if the id field does not set.
551
+ :param output: (DictData) A result data context that want to extract
552
+ and transfer to the `strategies` key in receive context.
553
+ :param to: (DictData) A received context data.
554
+ :param job_id: (str | None) A job ID if the `id` field does not set.
546
555
 
547
556
  :rtype: DictData
548
557
  """
@@ -555,7 +564,7 @@ class Job(BaseModel):
555
564
  )
556
565
 
557
566
  _id: str = self.id or job_id
558
- output: DictData = copy.deepcopy(output)
567
+ output: DictData = output.copy()
559
568
  errors: DictData = (
560
569
  {"errors": output.pop("errors", {})} if "errors" in output else {}
561
570
  )
@@ -584,9 +593,7 @@ class Job(BaseModel):
584
593
  *,
585
594
  run_id: str | None = None,
586
595
  parent_run_id: str | None = None,
587
- result: Result | None = None,
588
596
  event: Event | None = None,
589
- raise_error: bool = True,
590
597
  ) -> Result:
591
598
  """Job execution with passing dynamic parameters from the workflow
592
599
  execution. It will generate matrix values at the first step and run
@@ -595,22 +602,18 @@ class Job(BaseModel):
595
602
  This method be execution routing for call dynamic execution function
596
603
  with specific target `runs-on` value.
597
604
 
598
- :param params: An input parameters that use on job execution.
605
+ :param params: (DictData) A parameter data.
599
606
  :param run_id: (str) A job running ID.
600
- :param parent_run_id: (str) A parent workflow running ID.
601
- :param result: (Result) A result object for keeping context and status
602
- data.
603
- :param event: (Event) An event manager that pass to the
604
- PoolThreadExecutor.
605
- :param raise_error: (bool) A flag that all this method raise error to
606
- the strategy execution. Default is `True`.
607
+ :param parent_run_id: (str) A parent running ID.
608
+ :param event: (Event) An Event manager instance that use to cancel this
609
+ execution if it forces stopped by parent execution.
607
610
 
608
- :raise NotImplementedError: If the `runs-on` value does not implement.
611
+ :raise NotImplementedError: If the `runs-on` value does not implement on
612
+ this execution.
609
613
 
610
614
  :rtype: Result
611
615
  """
612
616
  result: Result = Result.construct_with_rs_or_id(
613
- result,
614
617
  run_id=run_id,
615
618
  parent_run_id=parent_run_id,
616
619
  id_logic=(self.id or "not-set"),
@@ -627,7 +630,6 @@ class Job(BaseModel):
627
630
  run_id=run_id,
628
631
  parent_run_id=parent_run_id,
629
632
  event=event,
630
- raise_error=raise_error,
631
633
  )
632
634
  elif self.runs_on.type == RunsOn.SELF_HOSTED: # pragma: no cov
633
635
  pass
@@ -638,15 +640,14 @@ class Job(BaseModel):
638
640
  run_id=run_id,
639
641
  parent_run_id=parent_run_id,
640
642
  event=event,
641
- raise_error=raise_error,
642
643
  )
643
644
 
644
645
  # pragma: no cov
645
646
  result.trace.error(
646
- f"[JOB]: Execution not support runs-on: {self.runs_on.type!r} yet."
647
+ f"[JOB]: Execute not support runs-on: {self.runs_on.type!r} yet."
647
648
  )
648
649
  raise NotImplementedError(
649
- f"Execution runs-on type: {self.runs_on.type} does not support yet."
650
+ f"Execute runs-on type: {self.runs_on.type} does not support yet."
650
651
  )
651
652
 
652
653
 
@@ -657,7 +658,6 @@ def local_execute_strategy(
657
658
  *,
658
659
  result: Result | None = None,
659
660
  event: Event | None = None,
660
- raise_error: bool = True,
661
661
  ) -> Result:
662
662
  """Local job strategy execution with passing dynamic parameters from the
663
663
  workflow execution to strategy matrix.
@@ -671,33 +671,33 @@ def local_execute_strategy(
671
671
  For each stage that execution with this strategy metrix, it will use the
672
672
  `set_outputs` method for reconstruct result context data.
673
673
 
674
- :raise JobException: If it has any error from `StageException` or
675
- `UtilException`.
676
-
677
674
  :param job: (Job) A job model that want to execute.
678
- :param strategy: A strategy metrix value that use on this execution.
679
- This value will pass to the `matrix` key for templating.
680
- :param params: A dynamic parameters that will deepcopy to the context.
681
- :param result: (Result) A result object for keeping context and status
682
- data.
683
- :param event: (Event) An event manager that pass to the PoolThreadExecutor.
684
- :param raise_error: (bool) A flag that all this method raise error
675
+ :param strategy: (DictData) A strategy metrix value. This value will pass
676
+ to the `matrix` key for templating in context data.
677
+ :param params: (DictData) A parameter data.
678
+ :param result: (Result) A Result instance for return context and status.
679
+ :param event: (Event) An Event manager instance that use to cancel this
680
+ execution if it forces stopped by parent execution.
681
+
682
+ :raise JobException: If stage execution raise any error as `StageException`
683
+ or `UtilException`.
685
684
 
686
685
  :rtype: Result
687
686
  """
688
- if result is None:
689
- result: Result = Result(run_id=gen_id(job.id or "not-set", unique=True))
690
-
691
- strategy_id: str = gen_id(strategy)
692
- context: DictData = copy.deepcopy(params)
693
- context.update({"matrix": strategy, "stages": {}})
694
-
687
+ result: Result = result or Result(
688
+ run_id=gen_id(job.id or "not-set", unique=True),
689
+ extras=job.extras,
690
+ )
695
691
  if strategy:
696
- result.trace.info(f"[JOB]: Execute Strategy: {strategy_id!r}")
692
+ strategy_id: str = gen_id(strategy)
693
+ result.trace.info(f"[JOB]: Start Strategy: {strategy_id!r}")
697
694
  result.trace.info(f"[JOB]: ... matrix: {strategy!r}")
698
695
  else:
699
- result.trace.info("[JOB]: Execute Empty-Strategy")
696
+ strategy_id: str = "EMPTY"
697
+ result.trace.info("[JOB]: Start Strategy: 'EMPTY'")
700
698
 
699
+ context: DictData = copy.deepcopy(params)
700
+ context.update({"matrix": strategy, "stages": {}})
701
701
  for stage in job.stages:
702
702
 
703
703
  if job.extras:
@@ -711,7 +711,7 @@ def local_execute_strategy(
711
711
  if event and event.is_set():
712
712
  error_msg: str = (
713
713
  "Job strategy was canceled from event that had set before "
714
- "strategy execution."
714
+ "job strategy execution."
715
715
  )
716
716
  return result.catch(
717
717
  status=CANCEL,
@@ -735,12 +735,7 @@ def local_execute_strategy(
735
735
  stage.set_outputs(rs.context, to=context)
736
736
  except (StageException, UtilException) as e:
737
737
  result.trace.error(f"[JOB]: {e.__class__.__name__}: {e}")
738
- if raise_error:
739
- raise JobException(
740
- f"Stage execution error: {e.__class__.__name__}: {e}"
741
- ) from None
742
-
743
- return result.catch(
738
+ result.catch(
744
739
  status=FAILED,
745
740
  context={
746
741
  strategy_id: {
@@ -750,13 +745,17 @@ def local_execute_strategy(
750
745
  },
751
746
  },
752
747
  )
748
+ raise JobException(
749
+ f"Stage raise: {e.__class__.__name__}: {e}"
750
+ ) from e
753
751
 
754
752
  if rs.status == FAILED:
755
753
  error_msg: str = (
756
- f"Job strategy was break because stage, {stage.iden}, "
757
- f"failed without raise error."
754
+ f"Strategy break because stage, {stage.iden!r}, return FAILED "
755
+ f"status."
758
756
  )
759
- return result.catch(
757
+ result.trace.warning(f"[JOB]: {error_msg}")
758
+ result.catch(
760
759
  status=FAILED,
761
760
  context={
762
761
  strategy_id: {
@@ -766,6 +765,7 @@ def local_execute_strategy(
766
765
  },
767
766
  },
768
767
  )
768
+ raise JobException(error_msg)
769
769
 
770
770
  return result.catch(
771
771
  status=SUCCESS,
@@ -785,22 +785,20 @@ def local_execute(
785
785
  run_id: str | None = None,
786
786
  parent_run_id: str | None = None,
787
787
  event: Event | None = None,
788
- raise_error: bool = True,
789
788
  ) -> Result:
790
789
  """Local job execution with passing dynamic parameters from the workflow
791
790
  execution or itself execution. It will generate matrix values at the first
792
791
  step and run multithread on this metrics to the `stages` field of this job.
793
792
 
794
- This method does not raise any JobException if it runs with
793
+ This method does not raise any `JobException` if it runs with
795
794
  multi-threading strategy.
796
795
 
797
- :param job: (Job) A job model that want to execute.
798
- :param params: (DictData) An input parameters that use on job execution.
799
- :param run_id: (str) A job running ID for this execution.
800
- :param parent_run_id: (str) A parent workflow running ID for this release.
801
- :param event: (Event) An event manager that pass to the PoolThreadExecutor.
802
- :param raise_error: (bool) A flag that all this method raise error to the
803
- strategy execution. Default is `True`.
796
+ :param job: (Job) A job model.
797
+ :param params: (DictData) A parameter data.
798
+ :param run_id: (str) A job running ID.
799
+ :param parent_run_id: (str) A parent workflow running ID.
800
+ :param event: (Event) An Event manager instance that use to cancel this
801
+ execution if it forces stopped by parent execution.
804
802
 
805
803
  :rtype: Result
806
804
  """
@@ -812,40 +810,12 @@ def local_execute(
812
810
  )
813
811
 
814
812
  event: Event = Event() if event is None else event
815
-
816
- # NOTE: Normal Job execution without parallel strategy matrix. It uses
817
- # for-loop to control strategy execution sequentially.
818
- if (not job.strategy.is_set()) or job.strategy.max_parallel == 1:
819
-
820
- for strategy in job.strategy.make():
821
-
822
- if event and event.is_set(): # pragma: no cov
823
- return result.catch(
824
- status=CANCEL,
825
- context={
826
- "errors": JobException(
827
- "Job strategy was canceled from event that had set "
828
- "before strategy execution."
829
- ).to_dict()
830
- },
831
- )
832
-
833
- local_execute_strategy(
834
- job,
835
- strategy,
836
- params,
837
- result=result,
838
- event=event,
839
- raise_error=raise_error,
840
- )
841
-
842
- return result
843
-
844
813
  fail_fast_flag: bool = job.strategy.fail_fast
845
814
  ls: str = "Fail-Fast" if fail_fast_flag else "All-Completed"
815
+ workers: int = job.strategy.max_parallel
846
816
  result.trace.info(
847
- f"[JOB]: Start multithreading: {job.strategy.max_parallel} threads "
848
- f"with {ls} mode."
817
+ f"[JOB]: {ls}-Execute: {job.id} with {workers} "
818
+ f"worker{'s' if workers > 1 else ''}."
849
819
  )
850
820
 
851
821
  if event and event.is_set(): # pragma: no cov
@@ -853,15 +823,14 @@ def local_execute(
853
823
  status=CANCEL,
854
824
  context={
855
825
  "errors": JobException(
856
- "Job strategy was canceled from event that had set "
857
- "before strategy execution."
826
+ "Job was canceled from event that had set before "
827
+ "local job execution."
858
828
  ).to_dict()
859
829
  },
860
830
  )
861
831
 
862
832
  with ThreadPoolExecutor(
863
- max_workers=job.strategy.max_parallel,
864
- thread_name_prefix="job_strategy_exec_",
833
+ max_workers=workers, thread_name_prefix="job_strategy_exec_"
865
834
  ) as executor:
866
835
 
867
836
  futures: list[Future] = [
@@ -872,7 +841,6 @@ def local_execute(
872
841
  params=params,
873
842
  result=result,
874
843
  event=event,
875
- raise_error=raise_error,
876
844
  )
877
845
  for strategy in job.strategy.make()
878
846
  ]
@@ -881,12 +849,9 @@ def local_execute(
881
849
  status: Status = SUCCESS
882
850
 
883
851
  if not fail_fast_flag:
884
- done = as_completed(futures, timeout=1800)
852
+ done: list[Future] = as_completed(futures)
885
853
  else:
886
- done, not_done = wait(
887
- futures, timeout=1800, return_when=FIRST_EXCEPTION
888
- )
889
-
854
+ done, not_done = wait(futures, return_when=FIRST_EXCEPTION)
890
855
  if len(done) != len(futures):
891
856
  result.trace.warning(
892
857
  "[JOB]: Set event for stop pending stage future."
@@ -895,10 +860,8 @@ def local_execute(
895
860
  for future in not_done:
896
861
  future.cancel()
897
862
 
898
- nd: str = (
899
- f", the strategies do not run is {not_done}" if not_done else ""
900
- )
901
- result.trace.debug(f"[JOB]: Strategy set Fail-Fast{nd}")
863
+ nd: str = f", strategies not run: {not_done}" if not_done else ""
864
+ result.trace.debug(f"... Strategy set Fail-Fast{nd}")
902
865
 
903
866
  for future in done:
904
867
  try:
@@ -906,10 +869,12 @@ def local_execute(
906
869
  except JobException as e:
907
870
  status = FAILED
908
871
  result.trace.error(
909
- f"[JOB]: {ls} Catch:\n\t{e.__class__.__name__}:\n\t{e}"
872
+ f"[JOB]: {ls}: {e.__class__.__name__}:{NEWLINE}{e}"
910
873
  )
911
- context.update({"errors": e.to_dict()})
912
-
874
+ if "errors" in context:
875
+ context["errors"].append(e.to_dict())
876
+ else:
877
+ context["errors"] = [e.to_dict()]
913
878
  return result.catch(status=status, context=context)
914
879
 
915
880
 
@@ -920,19 +885,17 @@ def self_hosted_execute(
920
885
  run_id: str | None = None,
921
886
  parent_run_id: str | None = None,
922
887
  event: Event | None = None,
923
- raise_error: bool = True,
924
888
  ) -> Result: # pragma: no cov
925
889
  """Self-Hosted job execution with passing dynamic parameters from the
926
890
  workflow execution or itself execution. It will make request to the
927
891
  self-hosted host url.
928
892
 
929
893
  :param job: (Job) A job model that want to execute.
930
- :param params: (DictData) An input parameters that use on job execution.
931
- :param run_id: (str) A job running ID for this execution.
932
- :param parent_run_id: (str) A parent workflow running ID for this release.
933
- :param event: (Event) An event manager that pass to the PoolThreadExecutor.
934
- :param raise_error: (bool) A flag that all this method raise error to the
935
- strategy execution.
894
+ :param params: (DictData) A parameter data.
895
+ :param run_id: (str) A job running ID.
896
+ :param parent_run_id: (str) A parent workflow running ID.
897
+ :param event: (Event) An Event manager instance that use to cancel this
898
+ execution if it forces stopped by parent execution.
936
899
 
937
900
  :rtype: Result
938
901
  """
@@ -948,8 +911,8 @@ def self_hosted_execute(
948
911
  status=CANCEL,
949
912
  context={
950
913
  "errors": JobException(
951
- "Job self-hosted execution was canceled from event that "
952
- "had set before start execution."
914
+ "Job was canceled from event that had set before start "
915
+ "self-hosted execution."
953
916
  ).to_dict()
954
917
  },
955
918
  )
@@ -964,20 +927,17 @@ def self_hosted_execute(
964
927
  "job": job.model_dump(),
965
928
  "params": params,
966
929
  "result": result.__dict__,
967
- "raise_error": raise_error,
968
930
  },
969
931
  )
970
932
  except requests.exceptions.RequestException as e:
971
933
  return result.catch(status=FAILED, context={"errors": to_dict(e)})
972
934
 
973
935
  if resp.status_code != 200:
974
- if raise_error:
975
- raise JobException(
976
- f"Job execution error from request to self-hosted: "
977
- f"{job.runs_on.args.host!r}"
978
- )
936
+ raise JobException(
937
+ f"Job execution error from request to self-hosted: "
938
+ f"{job.runs_on.args.host!r}"
939
+ )
979
940
 
980
- return result.catch(status=FAILED)
981
941
  return result.catch(status=SUCCESS)
982
942
 
983
943
 
@@ -988,7 +948,6 @@ def azure_batch_execute(
988
948
  run_id: str | None = None,
989
949
  parent_run_id: str | None = None,
990
950
  event: Event | None = None,
991
- raise_error: bool | None = None,
992
951
  ) -> Result: # pragma no cov
993
952
  """Azure Batch job execution that will run all job's stages on the Azure
994
953
  Batch Node and extract the result file to be returning context result.
@@ -1013,7 +972,6 @@ def azure_batch_execute(
1013
972
  :param run_id:
1014
973
  :param parent_run_id:
1015
974
  :param event:
1016
- :param raise_error:
1017
975
 
1018
976
  :rtype: Result
1019
977
  """
@@ -1028,13 +986,12 @@ def azure_batch_execute(
1028
986
  status=CANCEL,
1029
987
  context={
1030
988
  "errors": JobException(
1031
- "Job azure-batch execution was canceled from event that "
1032
- "had set before start execution."
989
+ "Job was canceled from event that had set before start "
990
+ "azure-batch execution."
1033
991
  ).to_dict()
1034
992
  },
1035
993
  )
1036
994
  print(params)
1037
- print(raise_error)
1038
995
  return result.catch(status=SUCCESS)
1039
996
 
1040
997
 
@@ -1045,7 +1002,6 @@ def docker_execution(
1045
1002
  run_id: str | None = None,
1046
1003
  parent_run_id: str | None = None,
1047
1004
  event: Event | None = None,
1048
- raise_error: bool | None = None,
1049
1005
  ):
1050
1006
  """Docker job execution.
1051
1007
 
@@ -1071,5 +1027,4 @@ def docker_execution(
1071
1027
  },
1072
1028
  )
1073
1029
  print(params)
1074
- print(raise_error)
1075
1030
  return result.catch(status=SUCCESS)
@@ -98,6 +98,7 @@ class Result:
98
98
  return cls(
99
99
  run_id=(run_id or gen_id(id_logic or "", unique=True)),
100
100
  parent_run_id=parent_run_id,
101
+ ts=get_dt_now(dynamic("tz", extras=extras)),
101
102
  extras=(extras or {}),
102
103
  )
103
104
  elif parent_run_id:
@@ -535,9 +535,7 @@ def schedule_task(
535
535
  current_release: datetime = current_date.replace(
536
536
  second=0, microsecond=0
537
537
  )
538
- if (
539
- first_date := q.first_queue.date
540
- ) > current_release: # pragma: no cov
538
+ if (first_date := q.queue[0].date) > current_release: # pragma: no cov
541
539
  result.trace.debug(
542
540
  f"[WORKFLOW]: Skip schedule "
543
541
  f"{first_date:%Y-%m-%d %H:%M:%S} for : {task.alias!r}"