ddeutil-workflow 0.0.19__py3-none-any.whl → 0.0.21__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.
@@ -1 +1 @@
1
- __version__: str = "0.0.19"
1
+ __version__: str = "0.0.21"
@@ -653,6 +653,20 @@ class CronJob:
653
653
 
654
654
 
655
655
  class CronJobYear(CronJob):
656
+ """The Cron Job Converter with Year extension object that generate datetime
657
+ dimension of cron job schedule format,
658
+
659
+ * * * * * * <command to execute>
660
+
661
+ (i) minute (0 - 59)
662
+ (ii) hour (0 - 23)
663
+ (iii) day of the month (1 - 31)
664
+ (iv) month (1 - 12)
665
+ (v) day of the week (0 - 6) (Sunday to Saturday; 7 is also Sunday
666
+ on some systems)
667
+ (vi) year (1990 - 2100)
668
+ """
669
+
656
670
  cron_length = 6
657
671
  cron_units = CRON_UNITS_YEAR
658
672
 
@@ -705,9 +719,17 @@ class CronRunner:
705
719
  else:
706
720
  self.date: datetime = datetime.now(tz=self.tz)
707
721
 
722
+ # NOTE: Add one second if the microsecond value more than 0.
723
+ if self.date.microsecond > 0:
724
+ self.date: datetime = self.date.replace(microsecond=0) + timedelta(
725
+ seconds=1
726
+ )
727
+
708
728
  # NOTE: Add one minute if the second value more than 0.
709
729
  if self.date.second > 0:
710
- self.date: datetime = self.date + timedelta(minutes=1)
730
+ self.date: datetime = self.date.replace(second=0) + timedelta(
731
+ minutes=1
732
+ )
711
733
 
712
734
  self.__start_date: datetime = self.date
713
735
  self.cron: CronJob | CronJobYear = cron
@@ -753,7 +775,7 @@ class CronRunner:
753
775
  not self.__shift_date(mode, reverse)
754
776
  for mode in ("year", "month", "day", "hour", "minute")
755
777
  ):
756
- return copy.deepcopy(self.date.replace(second=0, microsecond=0))
778
+ return copy.deepcopy(self.date)
757
779
 
758
780
  raise RecursionError("Unable to find execution time for schedule")
759
781
 
@@ -802,6 +824,10 @@ class CronRunner:
802
824
  # NOTE: Replace date that less than it mode to zero.
803
825
  self.date: datetime = replace_date(self.date, mode, reverse=reverse)
804
826
 
827
+ # NOTE: Replace second and microsecond values that change from
828
+ # the replace_date func with reverse flag.
829
+ self.date: datetime = self.date.replace(second=0, microsecond=0)
830
+
805
831
  if current_value != getattr(self.date, switch[mode]):
806
832
  return mode != "month"
807
833
 
@@ -15,7 +15,10 @@ from .exceptions import (
15
15
  UtilException,
16
16
  WorkflowException,
17
17
  )
18
- from .job import Job, Strategy
18
+ from .job import (
19
+ Job,
20
+ Strategy,
21
+ )
19
22
  from .on import (
20
23
  On,
21
24
  YearOn,
@@ -24,8 +27,6 @@ from .on import (
24
27
  from .scheduler import (
25
28
  Schedule,
26
29
  ScheduleWorkflow,
27
- Workflow,
28
- WorkflowTaskData,
29
30
  )
30
31
  from .stage import (
31
32
  BashStage,
@@ -34,7 +35,7 @@ from .stage import (
34
35
  PyStage,
35
36
  Stage,
36
37
  TriggerStage,
37
- handler_result,
38
+ extract_hook,
38
39
  )
39
40
  from .utils import (
40
41
  FILTERS,
@@ -70,3 +71,7 @@ from .utils import (
70
71
  str2template,
71
72
  tag,
72
73
  )
74
+ from .workflow import (
75
+ Workflow,
76
+ WorkflowTaskData,
77
+ )
@@ -101,6 +101,7 @@ class Re:
101
101
  #
102
102
  # Examples:
103
103
  # - tasks/function@dummy
104
+ #
104
105
  __re_task_fmt: str = r"""
105
106
  ^
106
107
  (?P<path>[^/@]+)
ddeutil/workflow/conf.py CHANGED
@@ -33,6 +33,29 @@ load_dotenv()
33
33
  env = os.getenv
34
34
 
35
35
 
36
+ @lru_cache
37
+ def get_logger(name: str):
38
+ """Return logger object with an input module name.
39
+
40
+ :param name: A module name that want to log.
41
+ """
42
+ lg = logging.getLogger(name)
43
+ formatter = logging.Formatter(
44
+ fmt=(
45
+ "%(asctime)s.%(msecs)03d (%(name)-10s, %(process)-5d, "
46
+ "%(thread)-5d) [%(levelname)-7s] %(message)-120s "
47
+ "(%(filename)s:%(lineno)s)"
48
+ ),
49
+ datefmt="%Y-%m-%d %H:%M:%S",
50
+ )
51
+ stream = logging.StreamHandler()
52
+ stream.setFormatter(formatter)
53
+ lg.addHandler(stream)
54
+
55
+ lg.setLevel(logging.DEBUG if config.debug else logging.INFO)
56
+ return lg
57
+
58
+
36
59
  class Config:
37
60
  """Config object for keeping application configuration on current session
38
61
  without changing when if the application still running.
@@ -77,6 +100,9 @@ class Config:
77
100
 
78
101
  # NOTE: Workflow
79
102
  max_job_parallel: int = int(env("WORKFLOW_CORE_MAX_JOB_PARALLEL", "2"))
103
+ max_job_exec_timeout: int = int(
104
+ env("WORKFLOW_CORE_MAX_JOB_EXEC_TIMEOUT", "600")
105
+ )
80
106
  max_poking_pool_worker: int = int(
81
107
  os.getenv("WORKFLOW_CORE_MAX_NUM_POKING", "4")
82
108
  )
@@ -98,12 +124,14 @@ class Config:
98
124
  os.getenv("WORKFLOW_API_ENABLE_ROUTE_SCHEDULE", "true")
99
125
  )
100
126
 
101
- def __init__(self):
127
+ def __init__(self) -> None:
128
+ # VALIDATE: the MAX_JOB_PARALLEL value should not less than 0.
102
129
  if self.max_job_parallel < 0:
103
130
  raise ValueError(
104
131
  f"``MAX_JOB_PARALLEL`` should more than 0 but got "
105
132
  f"{self.max_job_parallel}."
106
133
  )
134
+
107
135
  try:
108
136
  self.stop_boundary_delta: timedelta = timedelta(
109
137
  **json.loads(self.stop_boundary_delta_str)
@@ -287,29 +315,7 @@ def get_type(t: str, params: Config) -> AnyModelType:
287
315
 
288
316
 
289
317
  config = Config()
290
-
291
-
292
- @lru_cache
293
- def get_logger(name: str):
294
- """Return logger object with an input module name.
295
-
296
- :param name: A module name that want to log.
297
- """
298
- logger = logging.getLogger(name)
299
- formatter = logging.Formatter(
300
- fmt=(
301
- "%(asctime)s.%(msecs)03d (%(name)-10s, %(process)-5d, "
302
- "%(thread)-5d) [%(levelname)-7s] %(message)-120s "
303
- "(%(filename)s:%(lineno)s)"
304
- ),
305
- datefmt="%Y-%m-%d %H:%M:%S",
306
- )
307
- stream = logging.StreamHandler()
308
- stream.setFormatter(formatter)
309
- logger.addHandler(stream)
310
-
311
- logger.setLevel(logging.DEBUG if config.debug else logging.INFO)
312
- return logger
318
+ logger = get_logger("ddeutil.workflow")
313
319
 
314
320
 
315
321
  class BaseLog(BaseModel, ABC):
@@ -319,8 +325,8 @@ class BaseLog(BaseModel, ABC):
319
325
  """
320
326
 
321
327
  name: str = Field(description="A workflow name.")
322
- on: str = Field(description="A cronjob string of this piepline schedule.")
323
328
  release: datetime = Field(description="A release datetime.")
329
+ type: str = Field(description="A running type before logging.")
324
330
  context: DictData = Field(
325
331
  default_factory=dict,
326
332
  description=(
@@ -462,6 +468,9 @@ class FileLog(BaseLog):
462
468
  if not config.enable_write_log:
463
469
  return self
464
470
 
471
+ logger.debug(
472
+ f"({self.run_id}) [LOG]: Start writing log: {self.name!r}."
473
+ )
465
474
  log_file: Path = self.pointer() / f"{self.run_id}.log"
466
475
  log_file.write_text(
467
476
  json.dumps(
@@ -3,6 +3,10 @@
3
3
  # Licensed under the MIT License. See LICENSE in the project root for
4
4
  # license information.
5
5
  # ------------------------------------------------------------------------------
6
+ """Exception objects for this package do not do anything because I want to
7
+ create the lightweight workflow package. So, this module do just a exception
8
+ annotate for handle error only.
9
+ """
6
10
  from __future__ import annotations
7
11
 
8
12