mirror of
https://git.vectorsigma.ru/public/tubearchivist.git
synced 2026-08-04 18:19:35 +00:00
142 lines
4.4 KiB
Python
142 lines
4.4 KiB
Python
"""
|
|
Functionality:
|
|
- Handle scheduler config update
|
|
"""
|
|
|
|
from datetime import datetime
|
|
|
|
from appsettings.src.config import AppConfig
|
|
from celery.schedules import crontab
|
|
from common.src.env_settings import EnvironmentSettings
|
|
from django.utils import dateformat
|
|
from django_celery_beat.models import CrontabSchedule
|
|
from task.models import CustomPeriodicTask
|
|
from task.src.task_config import TASK_CONFIG
|
|
|
|
|
|
class ScheduleBuilder:
|
|
"""build schedule dicts for beat"""
|
|
|
|
SCHEDULES = {
|
|
"update_subscribed": "0 8 *",
|
|
"download_pending": "0 16 *",
|
|
"check_reindex": "0 12 *",
|
|
"thumbnail_check": "0 17 *",
|
|
"run_backup": "0 18 0",
|
|
"version_check": "0 11 *",
|
|
}
|
|
MSG = "message:setting"
|
|
|
|
def __init__(self):
|
|
self.config = AppConfig().config
|
|
|
|
def update_schedule(
|
|
self, task_name: str, cron_schedule: str, schedule_conf: dict | None
|
|
) -> None:
|
|
"""update schedule"""
|
|
if cron_schedule == "auto":
|
|
cron_schedule = self.SCHEDULES[task_name]
|
|
|
|
if cron_schedule:
|
|
_ = self.get_set_task(task_name, cron_schedule)
|
|
|
|
if schedule_conf:
|
|
for key, value in schedule_conf.items():
|
|
self.set_config(task_name, key, value)
|
|
|
|
def get_set_task(self, task_name, schedule=False):
|
|
"""get task"""
|
|
try:
|
|
task = CustomPeriodicTask.objects.get(name=task_name)
|
|
except CustomPeriodicTask.DoesNotExist:
|
|
description = TASK_CONFIG[task_name].get("title")
|
|
task = CustomPeriodicTask(
|
|
name=task_name,
|
|
task=task_name,
|
|
description=description,
|
|
)
|
|
|
|
if schedule:
|
|
task_crontab = self.get_set_cron_tab(schedule)
|
|
task.crontab = task_crontab
|
|
task.last_run_at = dateformat.make_aware(datetime.now())
|
|
task.save()
|
|
|
|
return task
|
|
|
|
@staticmethod
|
|
def get_set_cron_tab(schedule: str) -> CrontabSchedule:
|
|
"""needs to be validated before"""
|
|
kwargs = dict(zip(["minute", "hour", "day_of_week"], schedule.split()))
|
|
kwargs.update({"timezone": EnvironmentSettings.TZ})
|
|
task_crontab, _ = CrontabSchedule.objects.get_or_create(**kwargs)
|
|
|
|
return task_crontab
|
|
|
|
def set_config(self, task_name: str, key: str, value) -> None:
|
|
"""set task_config, validate before"""
|
|
try:
|
|
task = CustomPeriodicTask.objects.get(name=task_name)
|
|
task.task_config.update({key: value})
|
|
task.save()
|
|
except CustomPeriodicTask.DoesNotExist:
|
|
pass
|
|
|
|
|
|
class CrontabValidator:
|
|
"""validate crontab"""
|
|
|
|
CONFIG = {
|
|
"check_reindex": ["days"],
|
|
"run_backup": ["rotate"],
|
|
}
|
|
|
|
@staticmethod
|
|
def validate_fields(cron_fields: str) -> None:
|
|
"""expect 3 cron fields"""
|
|
if not len(cron_fields) == 3:
|
|
raise ValueError("expected three cron schedule fields")
|
|
|
|
@staticmethod
|
|
def validate_minute(minute_field: str):
|
|
"""expect minute int"""
|
|
if not minute_field.isdigit():
|
|
raise ValueError("Invalid value for minutes. Must be an integer.")
|
|
|
|
minutes = int(minute_field)
|
|
if not 0 <= minutes <= 59:
|
|
raise ValueError("Invalid minutes. Must be between 0 and 59.")
|
|
|
|
@staticmethod
|
|
def validate_cron_tab(minute, hour, day_of_week):
|
|
"""check if crontab can be created"""
|
|
try:
|
|
crontab(minute=minute, hour=hour, day_of_week=day_of_week)
|
|
except ValueError as err:
|
|
raise ValueError(f"invalid crontab: {err}") from err
|
|
|
|
def validate_cron(self, cron_expression):
|
|
"""create crontab schedule"""
|
|
if not cron_expression or cron_expression == "auto":
|
|
return
|
|
|
|
cron_fields = cron_expression.split()
|
|
self.validate_fields(cron_fields)
|
|
|
|
minute, hour, day_of_week = cron_fields
|
|
self.validate_minute(minute)
|
|
self.validate_cron_tab(minute, hour, day_of_week)
|
|
|
|
def validate_config(self, task_name: str, schedule_config: dict):
|
|
"""validate config for given task"""
|
|
if not schedule_config:
|
|
return
|
|
|
|
config_keys = self.CONFIG.get(task_name)
|
|
if not config_keys:
|
|
raise ValueError(f"task '{task_name}' doesn't take config")
|
|
|
|
for key in schedule_config:
|
|
if key not in config_keys:
|
|
raise ValueError(f"invalid config key for task '{task_name}'")
|