utils/cronutil/__init__.py
2021-06-24 18:30:44 +03:00

170 lines
7.3 KiB
Python

"""
Scheduler works only on a weekly scale. This is due to the use of the schedule package.
Target format: wD:HH:MM:SS, where:
wD - day of week unit: '1', '2', ... , '6', '7', '*'
HH - hour unit in 24-hours format: '00', '01', ... , '22', '23', '**'
MM - minute unit: '00', '01', ... , '58', '59', '**'
SS - second unit: '00', '01', ... , '58', '59', '**'
Units can be listed separated by commas.
Examples:
'*:**:**:**' - every second of every minute of every hour of every day
'*:**:**:*5' - every 05,15,25,35,45,55 seconds of every minute of every hour of every day
'*:2*:**:**' - every second of every minute of every 20,21,22,23 hours of every day
'*:2*:**:*5' - every 05,15,25,35,45,55 seconds of every minute of every 20,21,22,23 hours of every day
'3,5:2*:**:*5' - every 05,15,25,35,45,55 seconds every minute every 20,21,22,23 hours of Wednesday, Friday
'1,7:12:00:**' - every second 00 minutes 12 hours of Monday, Sunday
'1:07:00:00' - every 00 seconds 00 minutes 07 hours Monday
"""
from itertools import cycle
from time import sleep
from threading import Event, Thread
from . import schedule
class Scheduler:
"""
Control wrapper for the schedule package
"""
def __init__(self):
"""
Object constructor
"""
self.scheduler_entity = schedule.Scheduler()
self.scheduler_signal = None
def _start_thread(self, interval: int = 1):
"""
Running the scheduler with a thread in the background
:param interval: an integer specifying the period in seconds to start pending jobs
"""
signal = Event()
class ScheduleThread(Thread):
@classmethod
def run(cls):
while not signal.is_set():
self.scheduler_entity.run_pending()
sleep(interval)
ScheduleThread().start()
return signal
def start(self):
"""
Scheduler launch
"""
self.scheduler_signal = self._start_thread()
def stop(self):
"""
Stopping the Scheduler
"""
self.scheduler_signal.set()
def add(self, target: str, action):
"""
Adding a job to the execution queue
:param target: a string in the format wD:HH:MM:SS specifying the target of the launch time
:param action: a string with the name of the function to run
"""
target_undefined = target.split(':')
if len(target_undefined) == 4:
wd, hh, mm, ss = target_undefined[0], target_undefined[1], target_undefined[2], target_undefined[3]
if '*' in wd and '**' in hh and '**' in mm and '**' in ss:
self.scheduler_entity.every().seconds.do(action)
elif '*' in wd and '**' in hh and '**' in mm:
for element in self._expand_target(wd.split(','),
hh.split(','),
mm.split(','),
self._expand_time(ss, 'ss')):
ss = element[3]
self.scheduler_entity.every().minute.at(':' + ss).do(action)
elif '*' in wd and '**' in hh:
for element in self._expand_target(wd.split(','),
hh.split(','),
self._expand_time(mm, 'mm'),
self._expand_time(ss, 'ss')):
mm, ss = element[2], element[3]
self.scheduler_entity.every().hour.at(mm + ':' + ss).do(action)
pass
elif '*' in wd:
for element in self._expand_target(wd.split(','),
self._expand_time(hh, 'hh'),
self._expand_time(mm, 'mm'),
self._expand_time(ss, 'ss')):
hh, mm, ss = element[1], element[2], element[3]
self.scheduler_entity.every().day.at(hh + ':' + mm + ':' + ss).do(action)
else:
for element in self._expand_target(self._expand_time(wd, 'wd'),
self._expand_time(hh, 'hh'),
self._expand_time(mm, 'mm'),
self._expand_time(ss, 'ss')):
wd, hh, mm, ss = element[0], element[1], element[2], element[3]
if wd == '1':
self.scheduler_entity.every().monday.at(hh + ':' + mm + ':' + ss).do(action)
elif wd == '2':
self.scheduler_entity.every().tuesday.at(hh + ':' + mm + ':' + ss).do(action)
elif wd == '3':
self.scheduler_entity.every().wednesday.at(hh + ':' + mm + ':' + ss).do(action)
elif wd == '4':
self.scheduler_entity.every().thursday.at(hh + ':' + mm + ':' + ss).do(action)
elif wd == '5':
self.scheduler_entity.every().friday.at(hh + ':' + mm + ':' + ss).do(action)
elif wd == '6':
self.scheduler_entity.every().saturday.at(hh + ':' + mm + ':' + ss).do(action)
elif wd == '7':
self.scheduler_entity.every().sunday.at(hh + ':' + mm + ':' + ss).do(action)
@classmethod
def _expand_time(cls, time_raw: str, unit: str):
"""
Converts an undefined time units to a list of specific time units
:param time_raw: a string with time unit
:param unit: string description of the time unit
:return: list of specific time units
"""
if ',' in time_raw:
pass
elif '*' in time_raw and (unit == 'wd' or unit == 'hh' or unit == 'mm' or unit == 'ss'):
time_out, time_min, time_max = [], 0, 60
if unit == 'hh':
time_max = 24
if unit == 'wd':
time_min, time_max = 1, 8
for i in range(time_max):
out = time_raw.replace('**', format(i, '02d')).replace('*', str(i))
if 0 <= int(out) < time_max:
time_out.append(out)
return time_out
return time_raw.split(',')
@classmethod
def _expand_target(cls, wd: list, hh: list, mm: list, ss: list):
"""
Converts an undefined target to a list of specific target
:param wd: list with day of week time units
:param hh: list with hour time units
:param mm: list with minute time units
:param ss: list with second time units
:return: list of specific time targets
"""
cwd, chh, cmm, css = cycle(wd), cycle(hh), cycle(mm), cycle(ss)
target_defined = []
for a in range(len(wd)):
a_wd = next(cwd)
for b in range(len(hh)):
b_hh = next(chh)
for c in range(len(mm)):
c_mm = next(cmm)
for d in range(len(ss)):
d_ss = next(css)
target_defined.append([a_wd, b_hh, c_mm, d_ss])
return target_defined
if __name__ == "__main__":
pass