ddeutil-workflow 0.0.29__py3-none-any.whl → 0.0.31__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/__cron.py +1 -0
- ddeutil/workflow/__init__.py +5 -1
- ddeutil/workflow/api/api.py +2 -2
- ddeutil/workflow/conf.py +4 -0
- ddeutil/workflow/cron.py +77 -21
- ddeutil/workflow/exceptions.py +3 -0
- ddeutil/workflow/hook.py +3 -1
- ddeutil/workflow/params.py +18 -1
- ddeutil/workflow/result.py +1 -0
- ddeutil/workflow/scheduler.py +101 -67
- ddeutil/workflow/stage.py +13 -1
- ddeutil/workflow/utils.py +36 -10
- ddeutil/workflow/workflow.py +179 -141
- {ddeutil_workflow-0.0.29.dist-info → ddeutil_workflow-0.0.31.dist-info}/METADATA +17 -12
- ddeutil_workflow-0.0.31.dist-info/RECORD +25 -0
- ddeutil_workflow-0.0.29.dist-info/RECORD +0 -25
- {ddeutil_workflow-0.0.29.dist-info → ddeutil_workflow-0.0.31.dist-info}/LICENSE +0 -0
- {ddeutil_workflow-0.0.29.dist-info → ddeutil_workflow-0.0.31.dist-info}/WHEEL +0 -0
- {ddeutil_workflow-0.0.29.dist-info → ddeutil_workflow-0.0.31.dist-info}/top_level.txt +0 -0
ddeutil/workflow/workflow.py
CHANGED
@@ -29,7 +29,8 @@ from concurrent.futures import (
|
|
29
29
|
)
|
30
30
|
from dataclasses import field
|
31
31
|
from datetime import datetime, timedelta
|
32
|
-
from
|
32
|
+
from enum import Enum
|
33
|
+
from functools import partial, total_ordering
|
33
34
|
from heapq import heappop, heappush
|
34
35
|
from queue import Queue
|
35
36
|
from textwrap import dedent
|
@@ -53,29 +54,42 @@ from .utils import (
|
|
53
54
|
cut_id,
|
54
55
|
gen_id,
|
55
56
|
get_dt_now,
|
56
|
-
|
57
|
+
reach_next_minute,
|
58
|
+
wait_to_next_minute,
|
57
59
|
)
|
58
60
|
|
59
61
|
logger = get_logger("ddeutil.workflow")
|
60
62
|
|
61
63
|
__all__: TupleStr = (
|
64
|
+
"Release",
|
65
|
+
"ReleaseQueue",
|
66
|
+
"ReleaseType",
|
62
67
|
"Workflow",
|
63
|
-
"WorkflowRelease",
|
64
|
-
"WorkflowQueue",
|
65
68
|
"WorkflowTask",
|
66
69
|
)
|
67
70
|
|
68
71
|
|
72
|
+
class ReleaseType(str, Enum):
|
73
|
+
"""Release Type Enum support the type field on the Release dataclass."""
|
74
|
+
|
75
|
+
DEFAULT: str = "manual"
|
76
|
+
TASK: str = "task"
|
77
|
+
POKE: str = "poking"
|
78
|
+
|
79
|
+
|
69
80
|
@total_ordering
|
70
|
-
@dataclass(
|
71
|
-
|
72
|
-
|
81
|
+
@dataclass(
|
82
|
+
config=ConfigDict(arbitrary_types_allowed=True, use_enum_values=True)
|
83
|
+
)
|
84
|
+
class Release:
|
85
|
+
"""Release Pydantic dataclass object that use for represent
|
86
|
+
the release data that use with the `workflow.release` method."""
|
73
87
|
|
74
88
|
date: datetime
|
75
89
|
offset: float
|
76
90
|
end_date: datetime
|
77
91
|
runner: CronRunner
|
78
|
-
type:
|
92
|
+
type: ReleaseType = field(default=ReleaseType.DEFAULT)
|
79
93
|
|
80
94
|
def __repr__(self) -> str:
|
81
95
|
return repr(f"{self.date:%Y-%m-%d %H:%M:%S}")
|
@@ -85,7 +99,7 @@ class WorkflowRelease:
|
|
85
99
|
|
86
100
|
@classmethod
|
87
101
|
def from_dt(cls, dt: datetime | str) -> Self:
|
88
|
-
"""Construct
|
102
|
+
"""Construct Release via datetime object only.
|
89
103
|
|
90
104
|
:param dt: A datetime object.
|
91
105
|
|
@@ -93,16 +107,19 @@ class WorkflowRelease:
|
|
93
107
|
"""
|
94
108
|
if isinstance(dt, str):
|
95
109
|
dt: datetime = datetime.fromisoformat(dt)
|
110
|
+
elif not isinstance(dt, datetime):
|
111
|
+
raise TypeError(
|
112
|
+
"The `from_dt` need argument type be str or datetime only."
|
113
|
+
)
|
96
114
|
|
97
115
|
return cls(
|
98
116
|
date=dt,
|
99
117
|
offset=0,
|
100
118
|
end_date=dt + timedelta(days=1),
|
101
119
|
runner=CronJob("* * * * *").schedule(dt.replace(tzinfo=config.tz)),
|
102
|
-
type="manual",
|
103
120
|
)
|
104
121
|
|
105
|
-
def __eq__(self, other:
|
122
|
+
def __eq__(self, other: Release | datetime) -> bool:
|
106
123
|
"""Override equal property that will compare only the same type or
|
107
124
|
datetime.
|
108
125
|
"""
|
@@ -112,7 +129,7 @@ class WorkflowRelease:
|
|
112
129
|
return self.date == other
|
113
130
|
return NotImplemented
|
114
131
|
|
115
|
-
def __lt__(self, other:
|
132
|
+
def __lt__(self, other: Release | datetime) -> bool:
|
116
133
|
"""Override equal property that will compare only the same type or
|
117
134
|
datetime.
|
118
135
|
"""
|
@@ -124,19 +141,19 @@ class WorkflowRelease:
|
|
124
141
|
|
125
142
|
|
126
143
|
@dataclass
|
127
|
-
class
|
128
|
-
"""Workflow Queue object that is management of
|
144
|
+
class ReleaseQueue:
|
145
|
+
"""Workflow Queue object that is management of Release objects."""
|
129
146
|
|
130
|
-
queue: list[
|
131
|
-
running: list[
|
132
|
-
complete: list[
|
147
|
+
queue: list[Release] = field(default_factory=list)
|
148
|
+
running: list[Release] = field(default_factory=list)
|
149
|
+
complete: list[Release] = field(default_factory=list)
|
133
150
|
|
134
151
|
@classmethod
|
135
152
|
def from_list(
|
136
|
-
cls, queue: list[datetime] | list[
|
153
|
+
cls, queue: list[datetime] | list[Release] | None = None
|
137
154
|
) -> Self:
|
138
|
-
"""Construct
|
139
|
-
with list of datetime or list of
|
155
|
+
"""Construct ReleaseQueue object from an input queue value that passing
|
156
|
+
with list of datetime or list of Release.
|
140
157
|
|
141
158
|
:raise TypeError: If the type of input queue does not valid.
|
142
159
|
|
@@ -148,14 +165,14 @@ class WorkflowQueue:
|
|
148
165
|
if isinstance(queue, list):
|
149
166
|
|
150
167
|
if all(isinstance(q, datetime) for q in queue):
|
151
|
-
return cls(queue=[
|
168
|
+
return cls(queue=[Release.from_dt(q) for q in queue])
|
152
169
|
|
153
|
-
if all(isinstance(q,
|
170
|
+
if all(isinstance(q, Release) for q in queue):
|
154
171
|
return cls(queue=queue)
|
155
172
|
|
156
173
|
raise TypeError(
|
157
|
-
"Type of the queue does not valid with
|
158
|
-
"or list of datetime or list of
|
174
|
+
"Type of the queue does not valid with ReleaseQueue "
|
175
|
+
"or list of datetime or list of Release."
|
159
176
|
)
|
160
177
|
|
161
178
|
@property
|
@@ -167,32 +184,25 @@ class WorkflowQueue:
|
|
167
184
|
return len(self.queue) > 0
|
168
185
|
|
169
186
|
@property
|
170
|
-
def first_queue(self) ->
|
171
|
-
"""Check an input
|
187
|
+
def first_queue(self) -> Release:
|
188
|
+
"""Check an input Release object is the first value of the
|
172
189
|
waiting queue.
|
173
190
|
|
174
191
|
:rtype: bool
|
175
192
|
"""
|
176
|
-
# NOTE: Old logic to peeking the first release from waiting queue.
|
177
|
-
#
|
178
|
-
# first_value: WorkflowRelease = heappop(self.queue)
|
179
|
-
# heappush(self.queue, first_value)
|
180
|
-
#
|
181
|
-
# return first_value
|
182
|
-
#
|
183
193
|
return self.queue[0]
|
184
194
|
|
185
|
-
def check_queue(self, value:
|
186
|
-
"""Check a
|
195
|
+
def check_queue(self, value: Release | datetime) -> bool:
|
196
|
+
"""Check a Release value already exists in list of tracking
|
187
197
|
queues.
|
188
198
|
|
189
|
-
:param value: A
|
199
|
+
:param value: A Release object that want to check it already in
|
190
200
|
queues.
|
191
201
|
|
192
202
|
:rtype: bool
|
193
203
|
"""
|
194
204
|
if isinstance(value, datetime):
|
195
|
-
value =
|
205
|
+
value = Release.from_dt(value)
|
196
206
|
|
197
207
|
return (
|
198
208
|
(value in self.queue)
|
@@ -200,13 +210,21 @@ class WorkflowQueue:
|
|
200
210
|
or (value in self.complete)
|
201
211
|
)
|
202
212
|
|
203
|
-
def remove_running(self, value:
|
204
|
-
"""Remove
|
213
|
+
def remove_running(self, value: Release) -> Self:
|
214
|
+
"""Remove Release in the running queue if it exists.
|
215
|
+
|
216
|
+
:rtype: Self
|
217
|
+
"""
|
205
218
|
if value in self.running:
|
206
219
|
self.running.remove(value)
|
207
220
|
|
208
|
-
|
209
|
-
|
221
|
+
return self
|
222
|
+
|
223
|
+
def mark_complete(self, value: Release) -> Self:
|
224
|
+
"""Push Release to the complete queue.
|
225
|
+
|
226
|
+
:rtype: Self
|
227
|
+
"""
|
210
228
|
heappush(self.complete, value)
|
211
229
|
|
212
230
|
# NOTE: Remove complete queue on workflow that keep more than the
|
@@ -216,7 +234,6 @@ class WorkflowQueue:
|
|
216
234
|
)
|
217
235
|
|
218
236
|
if num_complete_delete > 0:
|
219
|
-
print(num_complete_delete)
|
220
237
|
for _ in range(num_complete_delete):
|
221
238
|
heappop(self.complete)
|
222
239
|
|
@@ -464,14 +481,12 @@ class Workflow(BaseModel):
|
|
464
481
|
|
465
482
|
def release(
|
466
483
|
self,
|
467
|
-
release: datetime |
|
484
|
+
release: datetime | Release,
|
468
485
|
params: DictData,
|
469
486
|
*,
|
470
487
|
run_id: str | None = None,
|
471
488
|
log: type[Log] = None,
|
472
|
-
queue:
|
473
|
-
WorkflowQueue | list[datetime] | list[WorkflowRelease] | None
|
474
|
-
) = None,
|
489
|
+
queue: ReleaseQueue | None = None,
|
475
490
|
override_log_name: str | None = None,
|
476
491
|
) -> Result:
|
477
492
|
"""Release the workflow execution with overriding parameter with the
|
@@ -481,20 +496,20 @@ class Workflow(BaseModel):
|
|
481
496
|
This method allow workflow use log object to save the execution
|
482
497
|
result to log destination like file log to the local `/logs` directory.
|
483
498
|
|
484
|
-
|
485
|
-
- Initialize
|
499
|
+
Steps:
|
500
|
+
- Initialize ReleaseQueue and Release if they do not pass.
|
486
501
|
- Create release data for pass to parameter templating function.
|
487
502
|
- Execute this workflow with mapping release data to its parameters.
|
488
503
|
- Writing result log
|
489
504
|
- Remove this release on the running queue
|
490
505
|
- Push this release to complete queue
|
491
506
|
|
492
|
-
:param release: A release datetime or
|
507
|
+
:param release: A release datetime or Release object.
|
493
508
|
:param params: A workflow parameter that pass to execute method.
|
494
|
-
:param queue: A
|
509
|
+
:param queue: A ReleaseQueue that use for mark complete.
|
495
510
|
:param run_id: A workflow running ID for this release.
|
496
511
|
:param log: A log class that want to save the execution result.
|
497
|
-
:param queue: A
|
512
|
+
:param queue: A ReleaseQueue object.
|
498
513
|
:param override_log_name: An override logging name that use instead
|
499
514
|
the workflow name.
|
500
515
|
|
@@ -504,16 +519,17 @@ class Workflow(BaseModel):
|
|
504
519
|
name: str = override_log_name or self.name
|
505
520
|
run_id: str = run_id or gen_id(name, unique=True)
|
506
521
|
rs_release: Result = Result(run_id=run_id)
|
507
|
-
rs_release_type: str = "release"
|
508
522
|
|
509
|
-
|
510
|
-
|
511
|
-
|
523
|
+
if queue is not None and not isinstance(queue, ReleaseQueue):
|
524
|
+
raise TypeError(
|
525
|
+
"The queue argument should be ReleaseQueue object only."
|
526
|
+
)
|
512
527
|
|
513
|
-
# VALIDATE: Change release value to
|
528
|
+
# VALIDATE: Change release value to Release object.
|
529
|
+
rs_release_type: str = "release"
|
514
530
|
if isinstance(release, datetime):
|
515
531
|
rs_release_type: str = "datetime"
|
516
|
-
release:
|
532
|
+
release: Release = Release.from_dt(release)
|
517
533
|
|
518
534
|
logger.debug(
|
519
535
|
f"({cut_id(run_id)}) [RELEASE]: Start release - {name!r} : "
|
@@ -542,24 +558,26 @@ class Workflow(BaseModel):
|
|
542
558
|
)
|
543
559
|
|
544
560
|
rs.set_parent_run_id(run_id)
|
545
|
-
rs_log: Log = log.model_validate(
|
546
|
-
{
|
547
|
-
"name": name,
|
548
|
-
"release": release.date,
|
549
|
-
"type": release.type,
|
550
|
-
"context": rs.context,
|
551
|
-
"parent_run_id": rs.parent_run_id,
|
552
|
-
"run_id": rs.run_id,
|
553
|
-
}
|
554
|
-
)
|
555
561
|
|
556
562
|
# NOTE: Saving execution result to destination of the input log object.
|
557
563
|
logger.debug(f"({cut_id(run_id)}) [LOG]: Writing log: {name!r}.")
|
558
|
-
|
564
|
+
(
|
565
|
+
log.model_validate(
|
566
|
+
{
|
567
|
+
"name": name,
|
568
|
+
"release": release.date,
|
569
|
+
"type": release.type,
|
570
|
+
"context": rs.context,
|
571
|
+
"parent_run_id": rs.parent_run_id,
|
572
|
+
"run_id": rs.run_id,
|
573
|
+
}
|
574
|
+
).save(excluded=None)
|
575
|
+
)
|
559
576
|
|
560
577
|
# NOTE: Remove this release from running.
|
561
|
-
queue
|
562
|
-
|
578
|
+
if queue is not None:
|
579
|
+
queue.remove_running(release)
|
580
|
+
queue.mark_complete(release)
|
563
581
|
|
564
582
|
# NOTE: Remove the params key from the result context for deduplicate.
|
565
583
|
context: dict[str, Any] = rs.context
|
@@ -583,13 +601,21 @@ class Workflow(BaseModel):
|
|
583
601
|
self,
|
584
602
|
offset: float,
|
585
603
|
end_date: datetime,
|
586
|
-
queue:
|
604
|
+
queue: ReleaseQueue,
|
587
605
|
log: type[Log],
|
588
606
|
*,
|
589
607
|
force_run: bool = False,
|
590
|
-
) ->
|
591
|
-
"""Generate
|
592
|
-
the
|
608
|
+
) -> ReleaseQueue:
|
609
|
+
"""Generate Release from all on values from the on field and store them
|
610
|
+
to the ReleaseQueue object.
|
611
|
+
|
612
|
+
Steps:
|
613
|
+
- For-loop all the on value in the on field.
|
614
|
+
- Create Release object from the current date that not reach the end
|
615
|
+
date.
|
616
|
+
- Check this release do not store on the release queue object.
|
617
|
+
Generate the next date if it exists.
|
618
|
+
- Push this release to the release queue
|
593
619
|
|
594
620
|
:param offset: An offset in second unit for time travel.
|
595
621
|
:param end_date: An end datetime object.
|
@@ -598,7 +624,7 @@ class Workflow(BaseModel):
|
|
598
624
|
:param force_run: A flag that allow to release workflow if the log with
|
599
625
|
that release was pointed.
|
600
626
|
|
601
|
-
:rtype:
|
627
|
+
:rtype: ReleaseQueue
|
602
628
|
"""
|
603
629
|
for on in self.on:
|
604
630
|
|
@@ -610,30 +636,30 @@ class Workflow(BaseModel):
|
|
610
636
|
if runner.date > end_date:
|
611
637
|
continue
|
612
638
|
|
613
|
-
workflow_release =
|
639
|
+
workflow_release = Release(
|
614
640
|
date=runner.date,
|
615
641
|
offset=offset,
|
616
642
|
end_date=end_date,
|
617
643
|
runner=runner,
|
618
|
-
type=
|
644
|
+
type=ReleaseType.POKE,
|
619
645
|
)
|
620
646
|
|
621
647
|
while queue.check_queue(workflow_release) or (
|
622
648
|
log.is_pointed(name=self.name, release=workflow_release.date)
|
623
649
|
and not force_run
|
624
650
|
):
|
625
|
-
workflow_release =
|
651
|
+
workflow_release = Release(
|
626
652
|
date=runner.next,
|
627
653
|
offset=offset,
|
628
654
|
end_date=end_date,
|
629
655
|
runner=runner,
|
630
|
-
type=
|
656
|
+
type=ReleaseType.POKE,
|
631
657
|
)
|
632
658
|
|
633
659
|
if runner.date > end_date:
|
634
660
|
continue
|
635
661
|
|
636
|
-
# NOTE: Push the
|
662
|
+
# NOTE: Push the Release object to queue.
|
637
663
|
heappush(queue.queue, workflow_release)
|
638
664
|
|
639
665
|
return queue
|
@@ -656,6 +682,9 @@ class Workflow(BaseModel):
|
|
656
682
|
This method will observe its schedule that nearing to run with the
|
657
683
|
``self.release()`` method.
|
658
684
|
|
685
|
+
The limitation of this method is not allow run a date that less
|
686
|
+
than the current date.
|
687
|
+
|
659
688
|
:param start_date: A start datetime object.
|
660
689
|
:param params: A parameters that want to pass to the release method.
|
661
690
|
:param run_id: A workflow running ID for this poke.
|
@@ -672,6 +701,12 @@ class Workflow(BaseModel):
|
|
672
701
|
log: type[Log] = log or get_log()
|
673
702
|
run_id: str = run_id or gen_id(self.name, unique=True)
|
674
703
|
|
704
|
+
# VALIDATE: Check the periods value should gather than 0.
|
705
|
+
if periods <= 0:
|
706
|
+
raise WorkflowException(
|
707
|
+
"The period of poking should be int and grater or equal than 1."
|
708
|
+
)
|
709
|
+
|
675
710
|
# NOTE: If this workflow does not set the on schedule, it will return
|
676
711
|
# empty result.
|
677
712
|
if len(self.on) == 0:
|
@@ -681,23 +716,25 @@ class Workflow(BaseModel):
|
|
681
716
|
)
|
682
717
|
return []
|
683
718
|
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
719
|
+
# NOTE: Create the current date that change microsecond to 0
|
720
|
+
current_date: datetime = datetime.now(tz=config.tz).replace(
|
721
|
+
microsecond=0
|
722
|
+
)
|
688
723
|
|
689
724
|
# NOTE: Create start_date and offset variables.
|
690
|
-
current_date: datetime = datetime.now(tz=config.tz)
|
691
|
-
|
692
725
|
if start_date and start_date <= current_date:
|
693
|
-
start_date = start_date.replace(tzinfo=config.tz)
|
726
|
+
start_date = start_date.replace(tzinfo=config.tz).replace(
|
727
|
+
microsecond=0
|
728
|
+
)
|
694
729
|
offset: float = (current_date - start_date).total_seconds()
|
695
730
|
else:
|
731
|
+
# NOTE: Force change start date if it gathers than the current date,
|
732
|
+
# or it does not pass to this method.
|
696
733
|
start_date: datetime = current_date
|
697
734
|
offset: float = 0
|
698
735
|
|
699
|
-
# NOTE:
|
700
|
-
# value.
|
736
|
+
# NOTE: The end date is using to stop generate queue with an input
|
737
|
+
# periods value.
|
701
738
|
end_date: datetime = start_date + timedelta(minutes=periods)
|
702
739
|
|
703
740
|
logger.info(
|
@@ -708,18 +745,18 @@ class Workflow(BaseModel):
|
|
708
745
|
params: DictData = {} if params is None else params
|
709
746
|
results: list[Result] = []
|
710
747
|
|
711
|
-
# NOTE: Create empty
|
712
|
-
|
748
|
+
# NOTE: Create empty ReleaseQueue object.
|
749
|
+
q: ReleaseQueue = ReleaseQueue()
|
713
750
|
|
714
|
-
# NOTE:
|
715
|
-
|
716
|
-
|
717
|
-
end_date=
|
718
|
-
queue=wf_queue,
|
719
|
-
log=log,
|
720
|
-
force_run=force_run,
|
751
|
+
# NOTE: Create reusable partial function and add Release to the release
|
752
|
+
# queue object.
|
753
|
+
partial_queue = partial(
|
754
|
+
self.queue, offset, end_date, log=log, force_run=force_run
|
721
755
|
)
|
722
|
-
|
756
|
+
partial_queue(q)
|
757
|
+
|
758
|
+
# NOTE: Return the empty result if it does not have any Release.
|
759
|
+
if not q.is_queued:
|
723
760
|
logger.info(
|
724
761
|
f"({cut_id(run_id)}) [POKING]: {self.name!r} does not have "
|
725
762
|
f"any queue."
|
@@ -735,34 +772,27 @@ class Workflow(BaseModel):
|
|
735
772
|
|
736
773
|
futures: list[Future] = []
|
737
774
|
|
738
|
-
while
|
775
|
+
while q.is_queued:
|
739
776
|
|
740
|
-
# NOTE: Pop the latest
|
741
|
-
release:
|
777
|
+
# NOTE: Pop the latest Release object from the release queue.
|
778
|
+
release: Release = heappop(q.queue)
|
742
779
|
|
743
|
-
if (
|
744
|
-
release.date - get_dt_now(tz=config.tz, offset=offset)
|
745
|
-
).total_seconds() > 60:
|
780
|
+
if reach_next_minute(release.date, tz=config.tz, offset=offset):
|
746
781
|
logger.debug(
|
747
|
-
f"({cut_id(run_id)}) [POKING]:
|
748
|
-
f"release
|
782
|
+
f"({cut_id(run_id)}) [POKING]: The latest release, "
|
783
|
+
f"{release.date:%Y-%m-%d %H:%M:%S}, is not able to run "
|
784
|
+
f"on this minute"
|
749
785
|
)
|
750
|
-
heappush(
|
751
|
-
|
786
|
+
heappush(q.queue, release)
|
787
|
+
wait_to_next_minute(get_dt_now(tz=config.tz, offset=offset))
|
752
788
|
|
753
789
|
# WARNING: I already call queue poking again because issue
|
754
790
|
# about the every minute crontab.
|
755
|
-
|
756
|
-
offset,
|
757
|
-
end_date,
|
758
|
-
queue=wf_queue,
|
759
|
-
log=log,
|
760
|
-
force_run=force_run,
|
761
|
-
)
|
791
|
+
partial_queue(q)
|
762
792
|
continue
|
763
793
|
|
764
|
-
# NOTE: Push the latest
|
765
|
-
heappush(
|
794
|
+
# NOTE: Push the latest Release to the running queue.
|
795
|
+
heappush(q.running, release)
|
766
796
|
|
767
797
|
futures.append(
|
768
798
|
executor.submit(
|
@@ -770,17 +800,11 @@ class Workflow(BaseModel):
|
|
770
800
|
release=release,
|
771
801
|
params=params,
|
772
802
|
log=log,
|
773
|
-
queue=
|
803
|
+
queue=q,
|
774
804
|
)
|
775
805
|
)
|
776
806
|
|
777
|
-
|
778
|
-
offset,
|
779
|
-
end_date,
|
780
|
-
queue=wf_queue,
|
781
|
-
log=log,
|
782
|
-
force_run=force_run,
|
783
|
-
)
|
807
|
+
partial_queue(q)
|
784
808
|
|
785
809
|
# WARNING: This poking method does not allow to use fail-fast
|
786
810
|
# logic to catching parallel execution result.
|
@@ -1127,6 +1151,9 @@ class WorkflowTask:
|
|
1127
1151
|
|
1128
1152
|
This dataclass object is mapping 1-to-1 with workflow and cron runner
|
1129
1153
|
objects.
|
1154
|
+
|
1155
|
+
This dataclass has the release method for itself.
|
1156
|
+
|
1130
1157
|
"""
|
1131
1158
|
|
1132
1159
|
alias: str
|
@@ -1136,25 +1163,34 @@ class WorkflowTask:
|
|
1136
1163
|
|
1137
1164
|
def release(
|
1138
1165
|
self,
|
1139
|
-
release: datetime |
|
1166
|
+
release: datetime | Release | None = None,
|
1140
1167
|
run_id: str | None = None,
|
1141
1168
|
log: type[Log] = None,
|
1142
|
-
queue:
|
1143
|
-
WorkflowQueue | list[datetime] | list[WorkflowRelease] | None
|
1144
|
-
) = None,
|
1169
|
+
queue: ReleaseQueue | None = None,
|
1145
1170
|
) -> Result:
|
1146
1171
|
"""Release the workflow task data.
|
1147
1172
|
|
1148
|
-
:param release: A release datetime or
|
1173
|
+
:param release: A release datetime or Release object.
|
1149
1174
|
:param run_id: A workflow running ID for this release.
|
1150
1175
|
:param log: A log class that want to save the execution result.
|
1151
|
-
:param queue: A
|
1176
|
+
:param queue: A ReleaseQueue object that use to mark complete.
|
1152
1177
|
|
1153
1178
|
:rtype: Result
|
1154
1179
|
"""
|
1155
1180
|
log: type[Log] = log or get_log()
|
1156
1181
|
|
1157
1182
|
if release is None:
|
1183
|
+
|
1184
|
+
if queue is None:
|
1185
|
+
raise ValueError(
|
1186
|
+
"If pass None release value, you should to pass the queue"
|
1187
|
+
"for generate this release."
|
1188
|
+
)
|
1189
|
+
elif not isinstance(queue, ReleaseQueue):
|
1190
|
+
raise TypeError(
|
1191
|
+
"The queue argument should be ReleaseQueue object only."
|
1192
|
+
)
|
1193
|
+
|
1158
1194
|
if queue.check_queue(self.runner.date):
|
1159
1195
|
release = self.runner.next
|
1160
1196
|
|
@@ -1163,6 +1199,7 @@ class WorkflowTask:
|
|
1163
1199
|
else:
|
1164
1200
|
release = self.runner.date
|
1165
1201
|
|
1202
|
+
# NOTE: Call the workflow release method.
|
1166
1203
|
return self.workflow.release(
|
1167
1204
|
release=release,
|
1168
1205
|
params=self.values,
|
@@ -1175,12 +1212,13 @@ class WorkflowTask:
|
|
1175
1212
|
def queue(
|
1176
1213
|
self,
|
1177
1214
|
end_date: datetime,
|
1178
|
-
queue:
|
1215
|
+
queue: ReleaseQueue,
|
1179
1216
|
log: type[Log],
|
1180
1217
|
*,
|
1181
1218
|
force_run: bool = False,
|
1182
|
-
):
|
1183
|
-
"""Generate
|
1219
|
+
) -> ReleaseQueue:
|
1220
|
+
"""Generate Release from the runner field and store it to the
|
1221
|
+
ReleaseQueue object.
|
1184
1222
|
|
1185
1223
|
:param end_date: An end datetime object.
|
1186
1224
|
:param queue: A workflow queue object.
|
@@ -1188,35 +1226,35 @@ class WorkflowTask:
|
|
1188
1226
|
:param force_run: A flag that allow to release workflow if the log with
|
1189
1227
|
that release was pointed.
|
1190
1228
|
|
1191
|
-
:rtype:
|
1229
|
+
:rtype: ReleaseQueue
|
1192
1230
|
"""
|
1193
1231
|
if self.runner.date > end_date:
|
1194
1232
|
return queue
|
1195
1233
|
|
1196
|
-
workflow_release =
|
1234
|
+
workflow_release = Release(
|
1197
1235
|
date=self.runner.date,
|
1198
1236
|
offset=0,
|
1199
1237
|
end_date=end_date,
|
1200
1238
|
runner=self.runner,
|
1201
|
-
type=
|
1239
|
+
type=ReleaseType.TASK,
|
1202
1240
|
)
|
1203
1241
|
|
1204
1242
|
while queue.check_queue(workflow_release) or (
|
1205
1243
|
log.is_pointed(name=self.alias, release=workflow_release.date)
|
1206
1244
|
and not force_run
|
1207
1245
|
):
|
1208
|
-
workflow_release =
|
1246
|
+
workflow_release = Release(
|
1209
1247
|
date=self.runner.next,
|
1210
1248
|
offset=0,
|
1211
1249
|
end_date=end_date,
|
1212
1250
|
runner=self.runner,
|
1213
|
-
type=
|
1251
|
+
type=ReleaseType.TASK,
|
1214
1252
|
)
|
1215
1253
|
|
1216
1254
|
if self.runner.date > end_date:
|
1217
1255
|
return queue
|
1218
1256
|
|
1219
|
-
# NOTE: Push the
|
1257
|
+
# NOTE: Push the Release object to queue.
|
1220
1258
|
heappush(queue.queue, workflow_release)
|
1221
1259
|
|
1222
1260
|
return queue
|