old_console/rotation/services/cron_utils.py
2024-11-02 14:12:45 +03:00

157 lines
5.7 KiB
Python

import datetime
import logging
from celery.schedules import crontab
from django.conf import settings
from django_celery_beat.models import CrontabSchedule
from rotation.enums import Period, WeekDay, Month
_log = logging.getLogger(__name__)
def get_enum_indexes(enum_choises, serializer_value, start=1):
""" Iterate thru enum and get all index numbers that are used in serializer_value
So if we have a enum apple = a, banana = b and serializer value is ['a', 'b'], then
in result we will have a '1,2' string
:param enum_choises: Enum to iterate
:param serializer_value: Values to find
:param start: Start counter
:return: String like '1,2'
"""
index = start
result = ''
for value, label in enum_choises:
if value in serializer_value:
if len(result) > 0:
result += ',' + str(index)
else:
result = str(index)
index += 1
return result
def create_crontab(crontab_pattern=None,
*,
minute=None,
hour=None,
day_of_week=None,
day_of_month=None,
month_of_year=None):
""" Create new crontab filled with values from crontab_pattern overriden by explicit arguments """
if not crontab_pattern:
crontab_pattern = crontab()
return crontab(
minute=minute if minute is not None else crontab_pattern._orig_minute,
hour=hour if hour is not None else crontab_pattern._orig_hour,
day_of_week=day_of_week if day_of_week is not None else crontab_pattern._orig_day_of_week,
day_of_month=day_of_month if day_of_month is not None else crontab_pattern._orig_day_of_month,
month_of_year=month_of_year if month_of_year is not None else crontab_pattern._orig_month_of_year,
)
def crontab_to_schedule(crontab=None,
schedule=None,
*,
minute=None,
hour=None,
day_of_week=None,
day_of_month=None,
month_of_year=None):
""" Fill schedule with crontab info or explicit args,
if schedule is None new CrontabSchedule will be created """
if not schedule:
schedule = CrontabSchedule()
crontab = create_crontab(crontab,
minute=minute,
hour=hour,
day_of_week=day_of_week,
day_of_month=day_of_month,
month_of_year=month_of_year)
schedule.minute = crontab._orig_minute
schedule.hour = crontab._orig_hour
schedule.day_of_week = crontab._orig_day_of_week
schedule.day_of_month = crontab._orig_day_of_month
schedule.month_of_year = crontab._orig_month_of_year
return schedule
def serializer_to_model(serializer):
""" Convert serializer values to celery beat schedule
:param serializer: RotationSettingsSerializer filled with data
:return: CrontabSchedule filled with data but not saved
"""
schedule = CrontabSchedule()
if serializer.validated_data['schedule']['period'] == Period.DAY:
cur = serializer.validated_data['schedule']['time']
crontab_to_schedule(schedule=schedule, minute=str(cur.minute), hour=str(cur.hour))
elif serializer.validated_data['schedule']['period'] == Period.WEEK:
day_of_week = get_enum_indexes(WeekDay.choices,
serializer.validated_data['schedule']['week_day'],
start=0)
# also, need to set time
weeklycb = getattr(settings, 'WEEKLY_CRONTAB', crontab(minute='0', hour='0'))
crontab_to_schedule(weeklycb, schedule, day_of_week=day_of_week)
elif serializer.validated_data['schedule']['period'] == Period.MONTH:
month_of_year = get_enum_indexes(Month.choices,
serializer.validated_data['schedule']['month'])
# also, need to set day and time
monthlycb = getattr(settings, 'MONTHLY_CRONTAB', crontab(minute='0', hour='0', day_of_month='1'))
crontab_to_schedule(monthlycb, schedule, month_of_year=month_of_year)
return schedule
def schedule_to_dict(schedule):
""" Convert CrontabSchedule model to dict that can be used for ScheduleSerializer
:param schedule:
:return:
"""
data = {
'period': '',
'time': '',
'week_day': [],
'month': []
}
if schedule.month_of_year != '*':
index = 1
values = schedule.month_of_year.split(',')
data['period'] = Period.MONTH
for key, value in Month.choices:
if str(index) in values:
data['month'].append(key)
index += 1
return data
if schedule.day_of_week != '*':
index = 0
values = schedule.day_of_week.split(',')
data['period'] = Period.WEEK
for key, value in WeekDay.choices:
if str(index) in values:
data['week_day'].append(key)
index += 1
return data
# If we get here - we have a time record
data['period'] = Period.DAY
# we can have these options:
# - it's a int -> just convert to int
# - it's a * -> set 0
# - it contains - -> set 0
# - it contains , -> set 0
if schedule.minute == '*' or '-' in schedule.minute or ',' in schedule.minute:
minute = 0
else:
minute = int(schedule.minute)
if schedule.hour == '*' or '-' in schedule.hour or ',' in schedule.hour:
hour = 0
else:
hour = int(schedule.hour)
data['time'] = datetime.time(minute=minute, hour=hour)
return data