orionis 0.477.0__py3-none-any.whl → 0.479.0__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.
- orionis/console/contracts/event.py +178 -0
- orionis/console/contracts/schedule.py +124 -1
- orionis/console/enums/event.py +55 -0
- orionis/console/tasks/event.py +332 -0
- orionis/console/tasks/schedule.py +96 -242
- orionis/metadata/framework.py +1 -1
- {orionis-0.477.0.dist-info → orionis-0.479.0.dist-info}/METADATA +1 -1
- {orionis-0.477.0.dist-info → orionis-0.479.0.dist-info}/RECORD +12 -10
- orionis/console/enums/task.py +0 -42
- {orionis-0.477.0.dist-info → orionis-0.479.0.dist-info}/WHEEL +0 -0
- {orionis-0.477.0.dist-info → orionis-0.479.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.477.0.dist-info → orionis-0.479.0.dist-info}/top_level.txt +0 -0
- {orionis-0.477.0.dist-info → orionis-0.479.0.dist-info}/zip-safe +0 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from orionis.console.enums.event import Event as EventEntity
|
|
4
|
+
|
|
5
|
+
class IEvent(ABC):
|
|
6
|
+
|
|
7
|
+
@abstractmethod
|
|
8
|
+
def toEntity(
|
|
9
|
+
self
|
|
10
|
+
) -> EventEntity:
|
|
11
|
+
"""
|
|
12
|
+
Retrieve the event details as an EventEntity instance.
|
|
13
|
+
|
|
14
|
+
This method gathers all relevant attributes of the current Event object,
|
|
15
|
+
such as its signature, arguments, purpose, random delay, start and end dates,
|
|
16
|
+
and trigger, and returns them encapsulated in an EventEntity object.
|
|
17
|
+
|
|
18
|
+
Returns
|
|
19
|
+
-------
|
|
20
|
+
EventEntity
|
|
21
|
+
An EventEntity instance containing the event's signature, arguments,
|
|
22
|
+
purpose, random delay, start date, end date, and trigger.
|
|
23
|
+
"""
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def purpose(
|
|
28
|
+
self,
|
|
29
|
+
purpose: str
|
|
30
|
+
) -> 'IEvent':
|
|
31
|
+
"""
|
|
32
|
+
Set the purpose or description for the scheduled command.
|
|
33
|
+
|
|
34
|
+
This method assigns a human-readable purpose or description to the command
|
|
35
|
+
that is being scheduled. The purpose must be a non-empty string. This can
|
|
36
|
+
be useful for documentation, logging, or displaying information about the
|
|
37
|
+
scheduled job.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
purpose : str
|
|
42
|
+
The purpose or description to associate with the scheduled command.
|
|
43
|
+
Must be a non-empty string.
|
|
44
|
+
|
|
45
|
+
Returns
|
|
46
|
+
-------
|
|
47
|
+
Scheduler
|
|
48
|
+
Returns the current instance of the Scheduler to allow method chaining.
|
|
49
|
+
|
|
50
|
+
Raises
|
|
51
|
+
------
|
|
52
|
+
CLIOrionisValueError
|
|
53
|
+
If the provided purpose is not a non-empty string.
|
|
54
|
+
"""
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
@abstractmethod
|
|
58
|
+
def startDate(
|
|
59
|
+
self,
|
|
60
|
+
start_date: datetime
|
|
61
|
+
) -> 'IEvent':
|
|
62
|
+
"""
|
|
63
|
+
Set the start date for the event execution.
|
|
64
|
+
|
|
65
|
+
This method allows you to specify a start date for when the event should
|
|
66
|
+
begin execution. The start date must be a datetime instance.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
start_date : datetime
|
|
71
|
+
The start date for the event execution.
|
|
72
|
+
|
|
73
|
+
Returns
|
|
74
|
+
-------
|
|
75
|
+
Event
|
|
76
|
+
Returns the current instance of the Event to allow method chaining.
|
|
77
|
+
"""
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
@abstractmethod
|
|
81
|
+
def endDate(
|
|
82
|
+
self,
|
|
83
|
+
end_date: datetime
|
|
84
|
+
) -> 'IEvent':
|
|
85
|
+
"""
|
|
86
|
+
Set the end date for the event execution.
|
|
87
|
+
|
|
88
|
+
This method allows you to specify an end date for when the event should
|
|
89
|
+
stop executing. The end date must be a datetime instance.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
end_date : datetime
|
|
94
|
+
The end date for the event execution.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
Event
|
|
99
|
+
Returns the current instance of the Event to allow method chaining.
|
|
100
|
+
"""
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
@abstractmethod
|
|
104
|
+
def randomDelay(
|
|
105
|
+
self,
|
|
106
|
+
max_seconds: int = 10
|
|
107
|
+
) -> 'IEvent':
|
|
108
|
+
"""
|
|
109
|
+
Set a random delay for the event execution.
|
|
110
|
+
|
|
111
|
+
This method allows you to specify a random delay up to a maximum
|
|
112
|
+
number of seconds before the event is executed. This can be useful for
|
|
113
|
+
distributing load or avoiding collisions in scheduled tasks.
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
----------
|
|
117
|
+
max_seconds : int
|
|
118
|
+
The maximum number of seconds to wait before executing the event.
|
|
119
|
+
|
|
120
|
+
Returns
|
|
121
|
+
-------
|
|
122
|
+
Event
|
|
123
|
+
Returns the current instance of the Event to allow method chaining.
|
|
124
|
+
"""
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
@abstractmethod
|
|
128
|
+
def onceAt(
|
|
129
|
+
self,
|
|
130
|
+
date: datetime
|
|
131
|
+
) -> bool:
|
|
132
|
+
"""
|
|
133
|
+
Schedule the event to run once at a specific date and time.
|
|
134
|
+
|
|
135
|
+
This method allows you to schedule the event to execute once at a specified
|
|
136
|
+
date and time. The date must be a datetime instance.
|
|
137
|
+
|
|
138
|
+
Parameters
|
|
139
|
+
----------
|
|
140
|
+
date : datetime
|
|
141
|
+
The specific date and time when the event should run.
|
|
142
|
+
|
|
143
|
+
Returns
|
|
144
|
+
-------
|
|
145
|
+
bool
|
|
146
|
+
Returns True if the scheduling was successful.
|
|
147
|
+
"""
|
|
148
|
+
pass
|
|
149
|
+
|
|
150
|
+
@abstractmethod
|
|
151
|
+
def everySeconds(
|
|
152
|
+
self,
|
|
153
|
+
seconds: int
|
|
154
|
+
) -> bool:
|
|
155
|
+
"""
|
|
156
|
+
Schedule the event to run at fixed intervals measured in seconds.
|
|
157
|
+
|
|
158
|
+
This method configures the event to execute repeatedly at a specified interval
|
|
159
|
+
(in seconds). Optionally, the event can be restricted to a time window using
|
|
160
|
+
previously set start and end dates. A random delay (jitter) can also be applied
|
|
161
|
+
if configured.
|
|
162
|
+
|
|
163
|
+
Parameters
|
|
164
|
+
----------
|
|
165
|
+
seconds : int
|
|
166
|
+
The interval, in seconds, at which the event should be executed. Must be a positive integer.
|
|
167
|
+
|
|
168
|
+
Returns
|
|
169
|
+
-------
|
|
170
|
+
bool
|
|
171
|
+
Returns True if the interval scheduling was successfully configured.
|
|
172
|
+
|
|
173
|
+
Raises
|
|
174
|
+
------
|
|
175
|
+
CLIOrionisValueError
|
|
176
|
+
If `seconds` is not a positive integer.
|
|
177
|
+
"""
|
|
178
|
+
pass
|
|
@@ -1,4 +1,127 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import List, Optional
|
|
3
|
+
from orionis.console.tasks.event import Event
|
|
2
4
|
|
|
3
5
|
class ISchedule(ABC):
|
|
4
|
-
|
|
6
|
+
|
|
7
|
+
@abstractmethod
|
|
8
|
+
def command(
|
|
9
|
+
self,
|
|
10
|
+
signature: str,
|
|
11
|
+
args: Optional[List[str]] = None
|
|
12
|
+
) -> 'Event':
|
|
13
|
+
"""
|
|
14
|
+
Prepare an Event instance for a given command signature and its arguments.
|
|
15
|
+
|
|
16
|
+
This method validates the provided command signature and arguments, ensuring
|
|
17
|
+
that the command exists among the registered commands and that the arguments
|
|
18
|
+
are in the correct format. If validation passes, it creates and returns an
|
|
19
|
+
Event object representing the scheduled command, including its signature,
|
|
20
|
+
arguments, and description.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
signature : str
|
|
25
|
+
The unique signature identifying the command to be scheduled. Must be a non-empty string.
|
|
26
|
+
args : Optional[List[str]], optional
|
|
27
|
+
A list of string arguments to be passed to the command. Defaults to None.
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
Event
|
|
32
|
+
An Event instance containing the command signature, arguments, and its description.
|
|
33
|
+
|
|
34
|
+
Raises
|
|
35
|
+
------
|
|
36
|
+
ValueError
|
|
37
|
+
If the command signature is not a non-empty string, if the arguments are not a list
|
|
38
|
+
of strings or None, or if the command does not exist among the registered commands.
|
|
39
|
+
"""
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
async def start(self) -> None:
|
|
44
|
+
"""
|
|
45
|
+
Start the AsyncIO scheduler instance and keep it running.
|
|
46
|
+
|
|
47
|
+
This method initiates the AsyncIOScheduler which integrates with asyncio event loops
|
|
48
|
+
for asynchronous job execution. It ensures the scheduler starts properly within
|
|
49
|
+
an asyncio context and maintains the event loop active to process scheduled jobs.
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
None
|
|
54
|
+
This method does not return any value. It starts the AsyncIO scheduler and keeps it running.
|
|
55
|
+
"""
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
@abstractmethod
|
|
59
|
+
async def shutdown(self, wait=True) -> None:
|
|
60
|
+
"""
|
|
61
|
+
Shut down the AsyncIO scheduler instance asynchronously.
|
|
62
|
+
|
|
63
|
+
This method gracefully stops the AsyncIOScheduler that handles asynchronous job execution.
|
|
64
|
+
Using async ensures proper cleanup in asyncio environments.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
wait : bool, optional
|
|
69
|
+
If True, the method will wait until all currently executing jobs are completed before shutting down the scheduler.
|
|
70
|
+
If False, the scheduler will be shut down immediately without waiting for running jobs to finish. Default is True.
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
None
|
|
75
|
+
This method does not return any value. It shuts down the AsyncIO scheduler.
|
|
76
|
+
"""
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
@abstractmethod
|
|
80
|
+
async def remove(self, signature: str) -> bool:
|
|
81
|
+
"""
|
|
82
|
+
Remove a scheduled job from the AsyncIO scheduler asynchronously.
|
|
83
|
+
|
|
84
|
+
This method removes a job with the specified signature from both the internal
|
|
85
|
+
jobs dictionary and the AsyncIOScheduler instance. Using async ensures proper
|
|
86
|
+
cleanup in asyncio environments.
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
signature : str
|
|
91
|
+
The signature of the command/job to remove from the scheduler.
|
|
92
|
+
|
|
93
|
+
Returns
|
|
94
|
+
-------
|
|
95
|
+
bool
|
|
96
|
+
Returns True if the job was successfully removed, False if the job was not found.
|
|
97
|
+
|
|
98
|
+
Raises
|
|
99
|
+
------
|
|
100
|
+
ValueError
|
|
101
|
+
If the signature is not a non-empty string.
|
|
102
|
+
"""
|
|
103
|
+
pass
|
|
104
|
+
|
|
105
|
+
@abstractmethod
|
|
106
|
+
def events(self) -> list:
|
|
107
|
+
"""
|
|
108
|
+
Retrieve all scheduled jobs currently managed by the Scheduler.
|
|
109
|
+
|
|
110
|
+
This method loads and returns a list of dictionaries, each representing a scheduled job
|
|
111
|
+
managed by this Scheduler instance. Each dictionary contains details such as the command
|
|
112
|
+
signature, arguments, purpose, random delay, start and end dates, and additional job details.
|
|
113
|
+
|
|
114
|
+
Returns
|
|
115
|
+
-------
|
|
116
|
+
list of dict
|
|
117
|
+
A list where each element is a dictionary containing information about a scheduled job.
|
|
118
|
+
Each dictionary includes the following keys:
|
|
119
|
+
- 'signature': str, the command signature.
|
|
120
|
+
- 'args': list, the arguments passed to the command.
|
|
121
|
+
- 'purpose': str, the description or purpose of the job.
|
|
122
|
+
- 'random_delay': any, the random delay associated with the job (if any).
|
|
123
|
+
- 'start_date': str or None, the formatted start date and time of the job, or None if not set.
|
|
124
|
+
- 'end_date': str or None, the formatted end date and time of the job, or None if not set.
|
|
125
|
+
- 'details': any, additional details about the job.
|
|
126
|
+
"""
|
|
127
|
+
pass
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import List, Optional, Union
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from apscheduler.triggers.cron import CronTrigger
|
|
5
|
+
from apscheduler.triggers.date import DateTrigger
|
|
6
|
+
from apscheduler.triggers.interval import IntervalTrigger
|
|
7
|
+
from orionis.support.entities.base import BaseEntity
|
|
8
|
+
|
|
9
|
+
@dataclass(kw_only=True)
|
|
10
|
+
class Event(BaseEntity):
|
|
11
|
+
"""
|
|
12
|
+
Represents an event with scheduling and execution details.
|
|
13
|
+
|
|
14
|
+
Attributes
|
|
15
|
+
----------
|
|
16
|
+
signature : str
|
|
17
|
+
The unique identifier or signature of the event.
|
|
18
|
+
args : Optional[List[str]]
|
|
19
|
+
A list of arguments associated with the event.
|
|
20
|
+
purpose : Optional[str]
|
|
21
|
+
A description of the event's purpose.
|
|
22
|
+
random_delay : Optional[int]
|
|
23
|
+
An optional random delay (in seconds) before the event is triggered.
|
|
24
|
+
start_date : Optional[datetime]
|
|
25
|
+
The start date and time for the event.
|
|
26
|
+
end_date : Optional[datetime]
|
|
27
|
+
The end date and time for the event.
|
|
28
|
+
trigger : Optional[Union[CronTrigger, DateTrigger, IntervalTrigger]]
|
|
29
|
+
The trigger mechanism for the event.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Unique identifier for the event
|
|
34
|
+
signature: str
|
|
35
|
+
|
|
36
|
+
# List of arguments for the event, defaults to empty list if not provided
|
|
37
|
+
args: Optional[List[str]] = field(default_factory=list)
|
|
38
|
+
|
|
39
|
+
# Description of the event's purpose
|
|
40
|
+
purpose: Optional[str] = None
|
|
41
|
+
|
|
42
|
+
# Optional random delay (in seconds) before the event is triggered
|
|
43
|
+
random_delay: Optional[int] = None
|
|
44
|
+
|
|
45
|
+
# Start date and time for the event
|
|
46
|
+
start_date: Optional[datetime] = None
|
|
47
|
+
|
|
48
|
+
# End date and time for the event
|
|
49
|
+
end_date: Optional[datetime] = None
|
|
50
|
+
|
|
51
|
+
# Trigger mechanism for the event (cron, date, or interval)
|
|
52
|
+
trigger: Optional[Union[CronTrigger, DateTrigger, IntervalTrigger]] = None
|
|
53
|
+
|
|
54
|
+
# Optional details about the event
|
|
55
|
+
details: Optional[str] = None
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import random
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import List, Optional, Union
|
|
4
|
+
from apscheduler.triggers.cron import CronTrigger
|
|
5
|
+
from apscheduler.triggers.date import DateTrigger
|
|
6
|
+
from apscheduler.triggers.interval import IntervalTrigger
|
|
7
|
+
from orionis.console.contracts.event import IEvent
|
|
8
|
+
from orionis.console.enums.event import Event as EventEntity
|
|
9
|
+
from orionis.console.exceptions import CLIOrionisValueError
|
|
10
|
+
|
|
11
|
+
class Event(IEvent):
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
signature: str,
|
|
16
|
+
args: Optional[List[str]],
|
|
17
|
+
purpose: Optional[str] = None,
|
|
18
|
+
):
|
|
19
|
+
"""
|
|
20
|
+
Initialize a new Event instance.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
signature : str
|
|
25
|
+
The unique identifier or signature for the event. This is typically
|
|
26
|
+
used to distinguish between different events in the system.
|
|
27
|
+
args : Optional[List[str]]
|
|
28
|
+
A list of arguments required by the event. If not provided, an empty
|
|
29
|
+
list will be used.
|
|
30
|
+
purpose : Optional[str], optional
|
|
31
|
+
A human-readable description or purpose for the event, by default None.
|
|
32
|
+
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
None
|
|
36
|
+
This constructor does not return any value. It initializes the internal
|
|
37
|
+
state of the Event object.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
# Store the event's signature
|
|
41
|
+
self.__signature: str = signature
|
|
42
|
+
|
|
43
|
+
# Store the event's arguments, defaulting to an empty list if None is provided
|
|
44
|
+
self.__args: Optional[List[str]] = args if args is not None else []
|
|
45
|
+
|
|
46
|
+
# Store the event's purpose or description
|
|
47
|
+
self.__purpose: Optional[str] = purpose
|
|
48
|
+
|
|
49
|
+
# Initialize the random delay attribute (in seconds) as None
|
|
50
|
+
self.__random_delay: Optional[int] = None
|
|
51
|
+
|
|
52
|
+
# Initialize the start date for the event as None
|
|
53
|
+
self.__start_date: Optional[datetime] = None
|
|
54
|
+
|
|
55
|
+
# Initialize the end date for the event as None
|
|
56
|
+
self.__end_date: Optional[datetime] = None
|
|
57
|
+
|
|
58
|
+
# Initialize the trigger for the event as None; can be set to a Cron, Date, or Interval trigger
|
|
59
|
+
self.__trigger: Optional[Union[CronTrigger, DateTrigger, IntervalTrigger]] = None
|
|
60
|
+
|
|
61
|
+
# Initialize the details for the event as None; can be used to store additional information
|
|
62
|
+
self.__details: Optional[str] = None
|
|
63
|
+
|
|
64
|
+
def toEntity(
|
|
65
|
+
self
|
|
66
|
+
) -> EventEntity:
|
|
67
|
+
"""
|
|
68
|
+
Retrieve the event details as an EventEntity instance.
|
|
69
|
+
|
|
70
|
+
This method gathers all relevant attributes of the current Event object,
|
|
71
|
+
such as its signature, arguments, purpose, random delay, start and end dates,
|
|
72
|
+
and trigger, and returns them encapsulated in an EventEntity object.
|
|
73
|
+
|
|
74
|
+
Returns
|
|
75
|
+
-------
|
|
76
|
+
EventEntity
|
|
77
|
+
An EventEntity instance containing the event's signature, arguments,
|
|
78
|
+
purpose, random delay, start date, end date, and trigger.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
# Validate that the signature is set and is a non-empty string
|
|
82
|
+
if not self.__signature:
|
|
83
|
+
raise CLIOrionisValueError("Signature is required for the event.")
|
|
84
|
+
if not isinstance(self.__args, list):
|
|
85
|
+
raise CLIOrionisValueError("Args must be a list.")
|
|
86
|
+
if self.__purpose is not None and not isinstance(self.__purpose, str):
|
|
87
|
+
raise CLIOrionisValueError("Purpose must be a string or None.")
|
|
88
|
+
|
|
89
|
+
# Validate that start_date and end_date are datetime instances if they are set
|
|
90
|
+
if self.__start_date is not None and not isinstance(self.__start_date, datetime):
|
|
91
|
+
raise CLIOrionisValueError("Start date must be a datetime instance.")
|
|
92
|
+
if self.__end_date is not None and not isinstance(self.__end_date, datetime):
|
|
93
|
+
raise CLIOrionisValueError("End date must be a datetime instance.")
|
|
94
|
+
|
|
95
|
+
# Validate that trigger is one of the expected types if it is set
|
|
96
|
+
if self.__trigger is not None and not isinstance(self.__trigger, (CronTrigger, DateTrigger, IntervalTrigger)):
|
|
97
|
+
raise CLIOrionisValueError("Trigger must be a CronTrigger, DateTrigger, or IntervalTrigger.")
|
|
98
|
+
|
|
99
|
+
# Validate that random_delay is an integer if it is set
|
|
100
|
+
if self.__random_delay is not None and not isinstance(self.__random_delay, int):
|
|
101
|
+
raise CLIOrionisValueError("Random delay must be an integer or None.")
|
|
102
|
+
|
|
103
|
+
# Validate that details is a string if it is set
|
|
104
|
+
if self.__details is not None and not isinstance(self.__details, str):
|
|
105
|
+
raise CLIOrionisValueError("Details must be a string or None.")
|
|
106
|
+
|
|
107
|
+
# Construct and return an EventEntity with the current event's attributes
|
|
108
|
+
return EventEntity(
|
|
109
|
+
signature=self.__signature,
|
|
110
|
+
args=self.__args,
|
|
111
|
+
purpose=self.__purpose,
|
|
112
|
+
random_delay=self.__random_delay,
|
|
113
|
+
start_date=self.__start_date,
|
|
114
|
+
end_date=self.__end_date,
|
|
115
|
+
trigger=self.__trigger,
|
|
116
|
+
details=self.__details
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
def purpose(
|
|
120
|
+
self,
|
|
121
|
+
purpose: str
|
|
122
|
+
) -> 'Event':
|
|
123
|
+
"""
|
|
124
|
+
Set the purpose or description for the scheduled command.
|
|
125
|
+
|
|
126
|
+
This method assigns a human-readable purpose or description to the command
|
|
127
|
+
that is being scheduled. The purpose must be a non-empty string. This can
|
|
128
|
+
be useful for documentation, logging, or displaying information about the
|
|
129
|
+
scheduled job.
|
|
130
|
+
|
|
131
|
+
Parameters
|
|
132
|
+
----------
|
|
133
|
+
purpose : str
|
|
134
|
+
The purpose or description to associate with the scheduled command.
|
|
135
|
+
Must be a non-empty string.
|
|
136
|
+
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
Scheduler
|
|
140
|
+
Returns the current instance of the Scheduler to allow method chaining.
|
|
141
|
+
|
|
142
|
+
Raises
|
|
143
|
+
------
|
|
144
|
+
CLIOrionisValueError
|
|
145
|
+
If the provided purpose is not a non-empty string.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
# Validate that the purpose is a non-empty string
|
|
149
|
+
if not isinstance(purpose, str) or not purpose.strip():
|
|
150
|
+
raise CLIOrionisValueError("The purpose must be a non-empty string.")
|
|
151
|
+
|
|
152
|
+
# Set the internal purpose attribute
|
|
153
|
+
self.__purpose = purpose
|
|
154
|
+
|
|
155
|
+
# Return self to support method chaining
|
|
156
|
+
return self
|
|
157
|
+
|
|
158
|
+
def startDate(
|
|
159
|
+
self,
|
|
160
|
+
start_date: datetime
|
|
161
|
+
) -> 'Event':
|
|
162
|
+
"""
|
|
163
|
+
Set the start date for the event execution.
|
|
164
|
+
|
|
165
|
+
This method allows you to specify a start date for when the event should
|
|
166
|
+
begin execution. The start date must be a datetime instance.
|
|
167
|
+
|
|
168
|
+
Parameters
|
|
169
|
+
----------
|
|
170
|
+
start_date : datetime
|
|
171
|
+
The start date for the event execution.
|
|
172
|
+
|
|
173
|
+
Returns
|
|
174
|
+
-------
|
|
175
|
+
Event
|
|
176
|
+
Returns the current instance of the Event to allow method chaining.
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
# Validate that start_date is a datetime instance
|
|
180
|
+
if not isinstance(start_date, datetime):
|
|
181
|
+
raise CLIOrionisValueError("Start date must be a datetime instance.")
|
|
182
|
+
|
|
183
|
+
# Set the internal start date attribute
|
|
184
|
+
self.__start_date = start_date
|
|
185
|
+
|
|
186
|
+
# Return self to support method chaining
|
|
187
|
+
return self
|
|
188
|
+
|
|
189
|
+
def endDate(
|
|
190
|
+
self,
|
|
191
|
+
end_date: datetime
|
|
192
|
+
) -> 'Event':
|
|
193
|
+
"""
|
|
194
|
+
Set the end date for the event execution.
|
|
195
|
+
|
|
196
|
+
This method allows you to specify an end date for when the event should
|
|
197
|
+
stop executing. The end date must be a datetime instance.
|
|
198
|
+
|
|
199
|
+
Parameters
|
|
200
|
+
----------
|
|
201
|
+
end_date : datetime
|
|
202
|
+
The end date for the event execution.
|
|
203
|
+
|
|
204
|
+
Returns
|
|
205
|
+
-------
|
|
206
|
+
Event
|
|
207
|
+
Returns the current instance of the Event to allow method chaining.
|
|
208
|
+
"""
|
|
209
|
+
|
|
210
|
+
# Validate that end_date is a datetime instance
|
|
211
|
+
if not isinstance(end_date, datetime):
|
|
212
|
+
raise CLIOrionisValueError("End date must be a datetime instance.")
|
|
213
|
+
|
|
214
|
+
# Set the internal end date attribute
|
|
215
|
+
self.__end_date = end_date
|
|
216
|
+
|
|
217
|
+
# Return self to support method chaining
|
|
218
|
+
return self
|
|
219
|
+
|
|
220
|
+
def randomDelay(
|
|
221
|
+
self,
|
|
222
|
+
max_seconds: int = 10
|
|
223
|
+
) -> 'Event':
|
|
224
|
+
"""
|
|
225
|
+
Set a random delay for the event execution.
|
|
226
|
+
|
|
227
|
+
This method allows you to specify a random delay up to a maximum
|
|
228
|
+
number of seconds before the event is executed. This can be useful for
|
|
229
|
+
distributing load or avoiding collisions in scheduled tasks.
|
|
230
|
+
|
|
231
|
+
Parameters
|
|
232
|
+
----------
|
|
233
|
+
max_seconds : int
|
|
234
|
+
The maximum number of seconds to wait before executing the event.
|
|
235
|
+
|
|
236
|
+
Returns
|
|
237
|
+
-------
|
|
238
|
+
Event
|
|
239
|
+
Returns the current instance of the Event to allow method chaining.
|
|
240
|
+
"""
|
|
241
|
+
|
|
242
|
+
# Validate that max_seconds is a positive integer
|
|
243
|
+
if not isinstance(max_seconds, int) or max_seconds <= 0:
|
|
244
|
+
raise CLIOrionisValueError("max_seconds must be a positive integer.")
|
|
245
|
+
|
|
246
|
+
# Generate a random delay between 1 and max_seconds (inclusive)
|
|
247
|
+
self.__random_delay = random.randint(1, max_seconds)
|
|
248
|
+
|
|
249
|
+
# Return self to support method chaining
|
|
250
|
+
return self
|
|
251
|
+
|
|
252
|
+
def onceAt(
|
|
253
|
+
self,
|
|
254
|
+
date: datetime
|
|
255
|
+
) -> bool:
|
|
256
|
+
"""
|
|
257
|
+
Schedule the event to run once at a specific date and time.
|
|
258
|
+
|
|
259
|
+
This method allows you to schedule the event to execute once at a specified
|
|
260
|
+
date and time. The date must be a datetime instance.
|
|
261
|
+
|
|
262
|
+
Parameters
|
|
263
|
+
----------
|
|
264
|
+
date : datetime
|
|
265
|
+
The specific date and time when the event should run.
|
|
266
|
+
|
|
267
|
+
Returns
|
|
268
|
+
-------
|
|
269
|
+
bool
|
|
270
|
+
Returns True if the scheduling was successful.
|
|
271
|
+
"""
|
|
272
|
+
|
|
273
|
+
# Validate that date is a datetime instance
|
|
274
|
+
if not isinstance(date, datetime):
|
|
275
|
+
raise CLIOrionisValueError("The date must be a datetime instance.")
|
|
276
|
+
|
|
277
|
+
# Set the start and end dates to the specified date
|
|
278
|
+
self.__start_date = date
|
|
279
|
+
self.__end_date = date
|
|
280
|
+
|
|
281
|
+
# Set the trigger to a DateTrigger for the specified date
|
|
282
|
+
self.__trigger = DateTrigger(run_date=date)
|
|
283
|
+
|
|
284
|
+
# Optionally, set the details for the event
|
|
285
|
+
self.__details = f"Once At: {date.strftime('%Y-%m-%d %H:%M:%S')}"
|
|
286
|
+
|
|
287
|
+
# Return self to support method chaining
|
|
288
|
+
return True
|
|
289
|
+
|
|
290
|
+
def everySeconds(
|
|
291
|
+
self,
|
|
292
|
+
seconds: int
|
|
293
|
+
) -> bool:
|
|
294
|
+
"""
|
|
295
|
+
Schedule the event to run at fixed intervals measured in seconds.
|
|
296
|
+
|
|
297
|
+
This method configures the event to execute repeatedly at a specified interval
|
|
298
|
+
(in seconds). Optionally, the event can be restricted to a time window using
|
|
299
|
+
previously set start and end dates. A random delay (jitter) can also be applied
|
|
300
|
+
if configured.
|
|
301
|
+
|
|
302
|
+
Parameters
|
|
303
|
+
----------
|
|
304
|
+
seconds : int
|
|
305
|
+
The interval, in seconds, at which the event should be executed. Must be a positive integer.
|
|
306
|
+
|
|
307
|
+
Returns
|
|
308
|
+
-------
|
|
309
|
+
bool
|
|
310
|
+
Returns True if the interval scheduling was successfully configured.
|
|
311
|
+
|
|
312
|
+
Raises
|
|
313
|
+
------
|
|
314
|
+
CLIOrionisValueError
|
|
315
|
+
If `seconds` is not a positive integer.
|
|
316
|
+
"""
|
|
317
|
+
|
|
318
|
+
# Validate that the seconds parameter is a positive integer.
|
|
319
|
+
if not isinstance(seconds, int) or seconds <= 0:
|
|
320
|
+
raise CLIOrionisValueError("The interval must be a positive integer.")
|
|
321
|
+
|
|
322
|
+
# Configure the trigger to execute the event at the specified interval,
|
|
323
|
+
# using any previously set start_date, end_date, and random_delay (jitter).
|
|
324
|
+
self.__trigger = IntervalTrigger(
|
|
325
|
+
seconds=seconds,
|
|
326
|
+
start_date=self.__start_date,
|
|
327
|
+
end_date=self.__end_date,
|
|
328
|
+
jitter=self.__random_delay
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
# Indicate that the scheduling was successful.
|
|
332
|
+
return True
|
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import logging
|
|
3
|
-
from
|
|
4
|
-
from typing import List, Optional
|
|
3
|
+
from typing import Dict, List, Optional
|
|
5
4
|
import pytz
|
|
6
5
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler as APSAsyncIOScheduler
|
|
7
|
-
from apscheduler.triggers.cron import CronTrigger
|
|
8
|
-
from apscheduler.triggers.date import DateTrigger
|
|
9
|
-
from apscheduler.triggers.interval import IntervalTrigger
|
|
10
6
|
from orionis.app import Orionis
|
|
11
7
|
from orionis.console.contracts.reactor import IReactor
|
|
12
|
-
from orionis.console.
|
|
8
|
+
from orionis.console.contracts.schedule import ISchedule
|
|
13
9
|
from orionis.console.exceptions import CLIOrionisRuntimeError
|
|
14
|
-
from orionis.console.
|
|
10
|
+
from orionis.console.tasks.event import Event
|
|
15
11
|
from orionis.services.log.contracts.log_service import ILogger
|
|
16
12
|
|
|
17
|
-
class Scheduler():
|
|
13
|
+
class Scheduler(ISchedule):
|
|
18
14
|
|
|
19
15
|
def __init__(
|
|
20
16
|
self,
|
|
@@ -62,16 +58,14 @@ class Scheduler():
|
|
|
62
58
|
# Retrieve and store all available commands from the reactor.
|
|
63
59
|
self.__available_commands = self.__getCommands()
|
|
64
60
|
|
|
65
|
-
#
|
|
66
|
-
self.
|
|
61
|
+
# Initialize the jobs dictionary to keep track of scheduled jobs.
|
|
62
|
+
self.__events: Dict[str, Event] = {}
|
|
67
63
|
|
|
68
|
-
#
|
|
69
|
-
self.
|
|
70
|
-
self.__args: List[str] = None # Arguments for the command.
|
|
71
|
-
self.__purpose: str = None # Purpose or description of the scheduled job.
|
|
64
|
+
# Initialize the jobs list to keep track of all scheduled jobs.
|
|
65
|
+
self.__jobs: List[dict] = []
|
|
72
66
|
|
|
73
67
|
# Log the initialization of the Scheduler.
|
|
74
|
-
self.__logger.info("
|
|
68
|
+
self.__logger.info("Orionis scheduler initialized.")
|
|
75
69
|
|
|
76
70
|
def __getCommands(
|
|
77
71
|
self
|
|
@@ -166,56 +160,77 @@ class Scheduler():
|
|
|
166
160
|
# Return the description if the command exists, otherwise return None
|
|
167
161
|
return command_entry['description'] if command_entry else None
|
|
168
162
|
|
|
169
|
-
def
|
|
163
|
+
def __loadEvents(
|
|
170
164
|
self
|
|
171
165
|
) -> None:
|
|
172
166
|
"""
|
|
173
|
-
|
|
167
|
+
Load all scheduled events from the AsyncIOScheduler into the internal jobs dictionary.
|
|
174
168
|
|
|
175
|
-
This method
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
scheduling without retaining any previous settings.
|
|
169
|
+
This method retrieves all jobs currently managed by the AsyncIOScheduler and populates
|
|
170
|
+
the internal jobs dictionary with their details, including signature, arguments, purpose,
|
|
171
|
+
type, trigger, start date, and end date.
|
|
179
172
|
|
|
180
173
|
Returns
|
|
181
174
|
-------
|
|
182
175
|
None
|
|
183
|
-
This method does not return any value. It
|
|
176
|
+
This method does not return any value. It updates the internal jobs dictionary.
|
|
184
177
|
"""
|
|
185
178
|
|
|
186
|
-
|
|
187
|
-
self.
|
|
188
|
-
|
|
179
|
+
# Only load events if the jobs list is empty
|
|
180
|
+
if not self.__jobs:
|
|
181
|
+
|
|
182
|
+
# Iterate through all scheduled jobs in the AsyncIOScheduler
|
|
183
|
+
for signature, event in self.__events.items():
|
|
184
|
+
|
|
185
|
+
# Convert the event to its entity representation
|
|
186
|
+
entity = event.toEntity()
|
|
187
|
+
|
|
188
|
+
# Add the job to the internal jobs list
|
|
189
|
+
self.__jobs.append(entity.toDict())
|
|
190
|
+
|
|
191
|
+
# Create a unique key for the job based on its signature
|
|
192
|
+
self.__scheduler.add_job(
|
|
193
|
+
func= lambda command=signature, args=list(entity.args): self.__reactor.call(
|
|
194
|
+
command,
|
|
195
|
+
args
|
|
196
|
+
),
|
|
197
|
+
trigger=entity.trigger,
|
|
198
|
+
id=signature,
|
|
199
|
+
name=signature,
|
|
200
|
+
replace_existing=True
|
|
201
|
+
)
|
|
189
202
|
|
|
190
203
|
def command(
|
|
191
204
|
self,
|
|
192
205
|
signature: str,
|
|
193
206
|
args: Optional[List[str]] = None
|
|
194
|
-
) -> '
|
|
207
|
+
) -> 'Event':
|
|
195
208
|
"""
|
|
196
|
-
|
|
209
|
+
Prepare an Event instance for a given command signature and its arguments.
|
|
197
210
|
|
|
198
|
-
This method validates the provided command signature and arguments,
|
|
199
|
-
|
|
200
|
-
|
|
211
|
+
This method validates the provided command signature and arguments, ensuring
|
|
212
|
+
that the command exists among the registered commands and that the arguments
|
|
213
|
+
are in the correct format. If validation passes, it creates and returns an
|
|
214
|
+
Event object representing the scheduled command, including its signature,
|
|
215
|
+
arguments, and description.
|
|
201
216
|
|
|
202
217
|
Parameters
|
|
203
218
|
----------
|
|
204
219
|
signature : str
|
|
205
220
|
The unique signature identifying the command to be scheduled. Must be a non-empty string.
|
|
206
221
|
args : Optional[List[str]], optional
|
|
207
|
-
A list of string arguments to be passed to the command.
|
|
222
|
+
A list of string arguments to be passed to the command. Defaults to None.
|
|
208
223
|
|
|
209
224
|
Returns
|
|
210
225
|
-------
|
|
211
|
-
|
|
212
|
-
|
|
226
|
+
Event
|
|
227
|
+
An Event instance containing the command signature, arguments, and its description.
|
|
213
228
|
|
|
214
229
|
Raises
|
|
215
230
|
------
|
|
216
231
|
ValueError
|
|
217
|
-
If the signature is not a non-empty string, if the arguments are not a list
|
|
218
|
-
or if the command
|
|
232
|
+
If the command signature is not a non-empty string, if the arguments are not a list
|
|
233
|
+
of strings or None, or if the command does not exist among the registered commands.
|
|
219
234
|
"""
|
|
220
235
|
|
|
221
236
|
# Validate that the command signature is a non-empty string
|
|
@@ -230,203 +245,15 @@ class Scheduler():
|
|
|
230
245
|
if not self.__isAvailable(signature):
|
|
231
246
|
raise ValueError(f"The command '{signature}' is not available or does not exist.")
|
|
232
247
|
|
|
233
|
-
# Store the command
|
|
234
|
-
self.
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
# Store the provided arguments or default to an empty list
|
|
241
|
-
self.__args = args if args is not None else []
|
|
242
|
-
|
|
243
|
-
# Return self to support method chaining
|
|
244
|
-
return self
|
|
245
|
-
|
|
246
|
-
def purpose(
|
|
247
|
-
self,
|
|
248
|
-
purpose: str
|
|
249
|
-
) -> 'Scheduler':
|
|
250
|
-
"""
|
|
251
|
-
Set the purpose or description for the scheduled command.
|
|
252
|
-
|
|
253
|
-
This method assigns a human-readable purpose or description to the command
|
|
254
|
-
that is being scheduled. The purpose must be a non-empty string. This can
|
|
255
|
-
be useful for documentation, logging, or displaying information about the
|
|
256
|
-
scheduled job.
|
|
257
|
-
|
|
258
|
-
Parameters
|
|
259
|
-
----------
|
|
260
|
-
purpose : str
|
|
261
|
-
The purpose or description to associate with the scheduled command.
|
|
262
|
-
Must be a non-empty string.
|
|
263
|
-
|
|
264
|
-
Returns
|
|
265
|
-
-------
|
|
266
|
-
Scheduler
|
|
267
|
-
Returns the current instance of the Scheduler to allow method chaining.
|
|
268
|
-
|
|
269
|
-
Raises
|
|
270
|
-
------
|
|
271
|
-
ValueError
|
|
272
|
-
If the provided purpose is not a non-empty string.
|
|
273
|
-
"""
|
|
274
|
-
|
|
275
|
-
# Validate that the purpose is a non-empty string
|
|
276
|
-
if not isinstance(purpose, str) or not purpose.strip():
|
|
277
|
-
raise ValueError("The purpose must be a non-empty string.")
|
|
278
|
-
|
|
279
|
-
# Set the internal purpose attribute
|
|
280
|
-
self.__purpose = purpose
|
|
281
|
-
|
|
282
|
-
# Return self to support method chaining
|
|
283
|
-
return self
|
|
284
|
-
|
|
285
|
-
def onceAt(
|
|
286
|
-
self,
|
|
287
|
-
date: datetime
|
|
288
|
-
) -> bool:
|
|
289
|
-
"""
|
|
290
|
-
Schedule a command to run once at a specific date and time.
|
|
291
|
-
|
|
292
|
-
This method schedules the currently registered command to execute exactly once at the
|
|
293
|
-
specified datetime using the AsyncIOScheduler. The job is registered internally and
|
|
294
|
-
added to the scheduler instance.
|
|
295
|
-
|
|
296
|
-
Parameters
|
|
297
|
-
----------
|
|
298
|
-
date : datetime.datetime
|
|
299
|
-
The date and time at which the command should be executed. Must be a valid `datetime` instance.
|
|
300
|
-
|
|
301
|
-
Returns
|
|
302
|
-
-------
|
|
303
|
-
bool
|
|
304
|
-
Returns True if the job was successfully scheduled.
|
|
305
|
-
|
|
306
|
-
Raises
|
|
307
|
-
------
|
|
308
|
-
CLIOrionisRuntimeError
|
|
309
|
-
If the provided date is not a `datetime` instance or if there is an error while scheduling the job.
|
|
310
|
-
"""
|
|
311
|
-
|
|
312
|
-
try:
|
|
313
|
-
|
|
314
|
-
# Ensure the provided date is a valid datetime instance.
|
|
315
|
-
if not isinstance(date, datetime):
|
|
316
|
-
raise CLIOrionisRuntimeError(
|
|
317
|
-
"The date must be an instance of datetime."
|
|
318
|
-
)
|
|
319
|
-
|
|
320
|
-
# Register the job details internally.
|
|
321
|
-
self.__jobs[self.__command] = Task(
|
|
322
|
-
signature=self.__command,
|
|
323
|
-
args=self.__args,
|
|
324
|
-
purpose=self.__purpose,
|
|
325
|
-
trigger='once_at',
|
|
326
|
-
details=f"Date: {date.strftime('%Y-%m-%d %H:%M:%S')}, Timezone: {str(date.tzinfo) if date.tzinfo else 'UTC'}"
|
|
327
|
-
)
|
|
328
|
-
|
|
329
|
-
# Add the job to the scheduler.
|
|
330
|
-
self.__scheduler.add_job(
|
|
331
|
-
func= lambda command=self.__command, args=list(self.__args): self.__reactor.call(
|
|
332
|
-
command,
|
|
333
|
-
args
|
|
334
|
-
),
|
|
335
|
-
trigger=DateTrigger(
|
|
336
|
-
run_date=date
|
|
337
|
-
),
|
|
338
|
-
id=self.__command,
|
|
339
|
-
name=self.__command,
|
|
340
|
-
replace_existing=True
|
|
341
|
-
)
|
|
342
|
-
|
|
343
|
-
# Log the scheduling of the command.
|
|
344
|
-
self.__logger.info(
|
|
345
|
-
f"Scheduled command '{self.__command}' to run once at {date.strftime('%Y-%m-%d %H:%M:%S')}"
|
|
346
|
-
)
|
|
347
|
-
|
|
348
|
-
# Reset the internal state for future scheduling.
|
|
349
|
-
self.__reset()
|
|
350
|
-
|
|
351
|
-
# Return True to indicate successful scheduling.
|
|
352
|
-
return True
|
|
353
|
-
|
|
354
|
-
except Exception as e:
|
|
355
|
-
|
|
356
|
-
# Reraise known CLIOrionisRuntimeError exceptions.
|
|
357
|
-
if isinstance(e, CLIOrionisRuntimeError):
|
|
358
|
-
raise e
|
|
359
|
-
|
|
360
|
-
# Wrap and raise any other exceptions as CLIOrionisRuntimeError.
|
|
361
|
-
raise CLIOrionisRuntimeError(f"Error scheduling the job: {str(e)}")
|
|
362
|
-
|
|
363
|
-
def everySeconds(
|
|
364
|
-
self,
|
|
365
|
-
seconds: int
|
|
366
|
-
) -> 'Scheduler':
|
|
367
|
-
"""
|
|
368
|
-
Schedule a command to run at regular intervals in seconds.
|
|
369
|
-
|
|
370
|
-
This method sets the interval for the currently registered command to execute
|
|
371
|
-
every specified number of seconds. The job is registered internally and added
|
|
372
|
-
to the scheduler instance.
|
|
373
|
-
|
|
374
|
-
Parameters
|
|
375
|
-
----------
|
|
376
|
-
seconds : int
|
|
377
|
-
The interval in seconds at which the command should be executed. Must be a positive integer.
|
|
378
|
-
|
|
379
|
-
Returns
|
|
380
|
-
-------
|
|
381
|
-
Scheduler
|
|
382
|
-
Returns the current instance of the Scheduler to allow method chaining.
|
|
383
|
-
|
|
384
|
-
Raises
|
|
385
|
-
------
|
|
386
|
-
ValueError
|
|
387
|
-
If the provided seconds is not a positive integer.
|
|
388
|
-
"""
|
|
389
|
-
|
|
390
|
-
try:
|
|
391
|
-
|
|
392
|
-
# Validate that the seconds parameter is a positive integer.
|
|
393
|
-
if not isinstance(seconds, int) or seconds <= 0:
|
|
394
|
-
raise CLIOrionisValueError("The interval must be a positive integer.")
|
|
395
|
-
|
|
396
|
-
# Store the interval in the jobs dictionary.
|
|
397
|
-
self.__jobs[self.__command] = Task(
|
|
398
|
-
signature=self.__command,
|
|
399
|
-
args=self.__args,
|
|
400
|
-
purpose=self.__purpose,
|
|
401
|
-
trigger='every_seconds',
|
|
402
|
-
details=f"Interval: {seconds} seconds"
|
|
403
|
-
)
|
|
404
|
-
|
|
405
|
-
# Add the job to the scheduler with an interval trigger.
|
|
406
|
-
self.__scheduler.add_job(
|
|
407
|
-
func=lambda command=self.__command, args=list(self.__args): self.__reactor.call(
|
|
408
|
-
command,
|
|
409
|
-
args
|
|
410
|
-
),
|
|
411
|
-
trigger=IntervalTrigger(
|
|
412
|
-
seconds=seconds
|
|
413
|
-
),
|
|
414
|
-
id=self.__command,
|
|
415
|
-
name=self.__command,
|
|
416
|
-
replace_existing=True
|
|
417
|
-
)
|
|
418
|
-
|
|
419
|
-
# Return self to support method chaining.
|
|
420
|
-
return self
|
|
421
|
-
|
|
422
|
-
except Exception as e:
|
|
423
|
-
|
|
424
|
-
# Reraise known CLIOrionisValueError exceptions.
|
|
425
|
-
if isinstance(e, CLIOrionisValueError):
|
|
426
|
-
raise e
|
|
248
|
+
# Store the command and its arguments for scheduling
|
|
249
|
+
self.__events[signature] = Event(
|
|
250
|
+
signature=signature,
|
|
251
|
+
args=args or [],
|
|
252
|
+
purpose=self.__getDescription(signature)
|
|
253
|
+
)
|
|
427
254
|
|
|
428
|
-
|
|
429
|
-
|
|
255
|
+
# Return the Event instance for further scheduling configuration
|
|
256
|
+
return self.__events[signature]
|
|
430
257
|
|
|
431
258
|
async def start(self) -> None:
|
|
432
259
|
"""
|
|
@@ -445,6 +272,9 @@ class Scheduler():
|
|
|
445
272
|
# Start the AsyncIOScheduler to handle asynchronous jobs.
|
|
446
273
|
try:
|
|
447
274
|
|
|
275
|
+
# Load existing events into the scheduler
|
|
276
|
+
self.events()
|
|
277
|
+
|
|
448
278
|
# Ensure we're in an asyncio context
|
|
449
279
|
asyncio.get_running_loop()
|
|
450
280
|
|
|
@@ -565,22 +395,46 @@ class Scheduler():
|
|
|
565
395
|
# Job not found or other error
|
|
566
396
|
return False
|
|
567
397
|
|
|
568
|
-
def
|
|
398
|
+
def events(self) -> list:
|
|
569
399
|
"""
|
|
570
400
|
Retrieve all scheduled jobs currently managed by the Scheduler.
|
|
571
401
|
|
|
572
|
-
This method returns a
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
dictionary with details such as the signature, arguments, purpose, type, trigger, start time,
|
|
576
|
-
and end time.
|
|
402
|
+
This method loads and returns a list of dictionaries, each representing a scheduled job
|
|
403
|
+
managed by this Scheduler instance. Each dictionary contains details such as the command
|
|
404
|
+
signature, arguments, purpose, random delay, start and end dates, and additional job details.
|
|
577
405
|
|
|
578
406
|
Returns
|
|
579
407
|
-------
|
|
580
|
-
dict
|
|
581
|
-
A
|
|
582
|
-
|
|
408
|
+
list of dict
|
|
409
|
+
A list where each element is a dictionary containing information about a scheduled job.
|
|
410
|
+
Each dictionary includes the following keys:
|
|
411
|
+
- 'signature': str, the command signature.
|
|
412
|
+
- 'args': list, the arguments passed to the command.
|
|
413
|
+
- 'purpose': str, the description or purpose of the job.
|
|
414
|
+
- 'random_delay': any, the random delay associated with the job (if any).
|
|
415
|
+
- 'start_date': str or None, the formatted start date and time of the job, or None if not set.
|
|
416
|
+
- 'end_date': str or None, the formatted end date and time of the job, or None if not set.
|
|
417
|
+
- 'details': any, additional details about the job.
|
|
583
418
|
"""
|
|
584
419
|
|
|
585
|
-
#
|
|
586
|
-
|
|
420
|
+
# Ensure all events are loaded into the internal jobs list
|
|
421
|
+
self.__loadEvents()
|
|
422
|
+
|
|
423
|
+
# Initialize a list to hold details of each scheduled job
|
|
424
|
+
events: list = []
|
|
425
|
+
|
|
426
|
+
# Iterate over each job in the internal jobs list
|
|
427
|
+
for job in self.__jobs:
|
|
428
|
+
# Append a dictionary with relevant job details to the events list
|
|
429
|
+
events.append({
|
|
430
|
+
'signature': job['signature'],
|
|
431
|
+
'args': job['args'],
|
|
432
|
+
'purpose': job['purpose'],
|
|
433
|
+
'random_delay': job['random_delay'],
|
|
434
|
+
'start_date': job['start_date'].strftime('%Y-%m-%d %H:%M:%S') if job['start_date'] else None,
|
|
435
|
+
'end_date': job['end_date'].strftime('%Y-%m-%d %H:%M:%S') if job['end_date'] else None,
|
|
436
|
+
'details': job['details']
|
|
437
|
+
})
|
|
438
|
+
|
|
439
|
+
# Return the list of scheduled job details
|
|
440
|
+
return events
|
orionis/metadata/framework.py
CHANGED
|
@@ -18,9 +18,10 @@ orionis/console/commands/test.py,sha256=mWPB_m_nUrsakCT1N6fcCBYU9mYj1IC39n3ICbQp
|
|
|
18
18
|
orionis/console/commands/version.py,sha256=SUuNDJ40f2uq69OQUmPQXJKaa9Bm_iVRDPmBd7zc1Yc,3658
|
|
19
19
|
orionis/console/commands/workflow.py,sha256=NYOmjTSvm2o6AE4h9LSTZMFSYPQreNmEJtronyOxaYk,2451
|
|
20
20
|
orionis/console/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
+
orionis/console/contracts/event.py,sha256=pxoxNjk31bt6yGvUFRTo_TI_SaZZar6iSIJARWR6KbM,5170
|
|
21
22
|
orionis/console/contracts/kernel.py,sha256=mh4LlhEYHh3FuGZZQ0GBhD6ZLa5YQvaNj2r01IIHI5Y,826
|
|
22
23
|
orionis/console/contracts/reactor.py,sha256=Xeq7Zrw6WE5MV_XOQfiQEchAFbb6-0TjLpjWOxYW--g,4554
|
|
23
|
-
orionis/console/contracts/schedule.py,sha256=
|
|
24
|
+
orionis/console/contracts/schedule.py,sha256=eGjcOH7kgdf0fWDZRfOFUQsIx4E8G38ayX5JwpkpN8E,4977
|
|
24
25
|
orionis/console/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
26
|
orionis/console/core/reactor.py,sha256=Hd7T-jNG_tzhpJXRztjDSKCtm7-3LOh5lcQ__cIchMk,30172
|
|
26
27
|
orionis/console/dumper/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -33,7 +34,7 @@ orionis/console/dynamic/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeR
|
|
|
33
34
|
orionis/console/dynamic/contracts/progress_bar.py,sha256=NYebL2h-vg2t2H6IhJjuC37gglRkpT-MW71wbJtpLNg,1784
|
|
34
35
|
orionis/console/enums/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
36
|
orionis/console/enums/command.py,sha256=lCfVp2vnDojJN2gjdVxE_XU3mRjZZgOIxPfBVQYo9w4,1278
|
|
36
|
-
orionis/console/enums/
|
|
37
|
+
orionis/console/enums/event.py,sha256=XRV7N14N5HHt-c0HqYhrbKv4n2P7ZOCcBT_3OAQzenU,1929
|
|
37
38
|
orionis/console/exceptions/__init__.py,sha256=0qlHNuHMVZO87M-rP8lThUUyljRM1jSFNikaxSCjSbw,366
|
|
38
39
|
orionis/console/exceptions/cli_exception.py,sha256=HsZ_vSeNiJWQ0gznVFNcIdhM0Bj_vkSRVBJs0wMjEKY,1141
|
|
39
40
|
orionis/console/exceptions/cli_orionis_value_error.py,sha256=RQP0HRwxDG8hxFOT1kUoZ1Ab1CZ1KLoSIl5yqlmgG4M,1147
|
|
@@ -48,7 +49,8 @@ orionis/console/output/contracts/executor.py,sha256=7l3kwnvv6GlH9EYk0v94YE1olex_
|
|
|
48
49
|
orionis/console/output/enums/__init__.py,sha256=LAaAxg-DpArCjf_jqZ0_9s3p8899gntDYkSU_ppTdC8,66
|
|
49
50
|
orionis/console/output/enums/styles.py,sha256=6a4oQCOBOKMh2ARdeq5GlIskJ3wjiylYmh66tUKKmpQ,4053
|
|
50
51
|
orionis/console/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
51
|
-
orionis/console/tasks/
|
|
52
|
+
orionis/console/tasks/event.py,sha256=NdOht_yXqKW0EIsIVrctIgOhQDWAR5fuMPEF05zTWtI,12029
|
|
53
|
+
orionis/console/tasks/schedule.py,sha256=L0l8GqPWsVtIEX1rifw3MeKkcAAOvu9ODdLmhUyyKTA,16802
|
|
52
54
|
orionis/container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
53
55
|
orionis/container/container.py,sha256=p7kJ-hwnDattTWCArt0ypol4bW3M334hIZ2FAQhID-w,87570
|
|
54
56
|
orionis/container/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -194,7 +196,7 @@ orionis/foundation/providers/reactor_provider.py,sha256=P0KQcp4AFKTrD6BStGfCTqhG
|
|
|
194
196
|
orionis/foundation/providers/testing_provider.py,sha256=SrJRpdvcblx9WvX7x9Y3zc7OQfiTf7la0HAJrm2ESlE,3725
|
|
195
197
|
orionis/foundation/providers/workers_provider.py,sha256=oa_2NIDH6UxZrtuGkkoo_zEoNIMGgJ46vg5CCgAm7wI,3926
|
|
196
198
|
orionis/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
197
|
-
orionis/metadata/framework.py,sha256=
|
|
199
|
+
orionis/metadata/framework.py,sha256=PYshO2bwCnp97QmgRrzTX5U6DHY_qu1YKgy9kTlKVyc,4109
|
|
198
200
|
orionis/metadata/package.py,sha256=k7Yriyp5aUcR-iR8SK2ec_lf0_Cyc-C7JczgXa-I67w,16039
|
|
199
201
|
orionis/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
200
202
|
orionis/services/asynchrony/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -365,7 +367,7 @@ orionis/test/validators/web_report.py,sha256=n9BfzOZz6aEiNTypXcwuWbFRG0OdHNSmCNu
|
|
|
365
367
|
orionis/test/validators/workers.py,sha256=rWcdRexINNEmGaO7mnc1MKUxkHKxrTsVuHgbnIfJYgc,1206
|
|
366
368
|
orionis/test/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
367
369
|
orionis/test/view/render.py,sha256=f-zNhtKSg9R5Njqujbg2l2amAs2-mRVESneLIkWOZjU,4082
|
|
368
|
-
orionis-0.
|
|
370
|
+
orionis-0.479.0.dist-info/licenses/LICENCE,sha256=JhC-z_9mbpUrCfPjcl3DhDA8trNDMzb57cvRSam1avc,1463
|
|
369
371
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
370
372
|
tests/container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
371
373
|
tests/container/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -512,8 +514,8 @@ tests/testing/validators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
512
514
|
tests/testing/validators/test_testing_validators.py,sha256=WPo5GxTP6xE-Dw3X1vZoqOMpb6HhokjNSbgDsDRDvy4,16588
|
|
513
515
|
tests/testing/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
514
516
|
tests/testing/view/test_render.py,sha256=tnnMBwS0iKUIbogLvu-7Rii50G6Koddp3XT4wgdFEYM,1050
|
|
515
|
-
orionis-0.
|
|
516
|
-
orionis-0.
|
|
517
|
-
orionis-0.
|
|
518
|
-
orionis-0.
|
|
519
|
-
orionis-0.
|
|
517
|
+
orionis-0.479.0.dist-info/METADATA,sha256=SJeq-4OG1PSuNSQA9NgyExYAVHasB7U6z54gMKgwQTY,4801
|
|
518
|
+
orionis-0.479.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
519
|
+
orionis-0.479.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
|
|
520
|
+
orionis-0.479.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
|
|
521
|
+
orionis-0.479.0.dist-info/RECORD,,
|
orionis/console/enums/task.py
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
from typing import List, Optional
|
|
3
|
-
from orionis.support.entities.base import BaseEntity
|
|
4
|
-
|
|
5
|
-
@dataclass(kw_only=True)
|
|
6
|
-
class Task(BaseEntity):
|
|
7
|
-
"""
|
|
8
|
-
Represents a task entity containing metadata for execution and description.
|
|
9
|
-
|
|
10
|
-
Parameters
|
|
11
|
-
----------
|
|
12
|
-
signature : str
|
|
13
|
-
The unique identifier or signature of the task.
|
|
14
|
-
args : Optional[List[str]], optional
|
|
15
|
-
List of arguments required by the task, by default None.
|
|
16
|
-
purpose : str, optional
|
|
17
|
-
Brief description of the task's purpose, by default None.
|
|
18
|
-
trigger : str, optional
|
|
19
|
-
Event or condition that triggers the task, by default None.
|
|
20
|
-
details : str, optional
|
|
21
|
-
Additional details or information about the task, by default None.
|
|
22
|
-
|
|
23
|
-
Returns
|
|
24
|
-
-------
|
|
25
|
-
Task
|
|
26
|
-
An instance of the Task class with the specified metadata.
|
|
27
|
-
"""
|
|
28
|
-
|
|
29
|
-
# Unique identifier for the task
|
|
30
|
-
signature: str
|
|
31
|
-
|
|
32
|
-
# List of arguments required by the task (optional)
|
|
33
|
-
args: Optional[List[str]] = None
|
|
34
|
-
|
|
35
|
-
# Brief description of the task's purpose (optional)
|
|
36
|
-
purpose: str = None
|
|
37
|
-
|
|
38
|
-
# Event or condition that triggers the task (optional)
|
|
39
|
-
trigger: str = None
|
|
40
|
-
|
|
41
|
-
# Additional details or information about the task (optional)
|
|
42
|
-
details: str = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|