Skip to content
Snippets Groups Projects
Verified Commit 5158e501 authored by Nik | Klampfradler's avatar Nik | Klampfradler
Browse files

Support default schedules for periodic tasks

parent eaa37382
No related branches found
No related tags found
1 merge request!919Resolve "Pre-define periodic tasks"
Pipeline #50584 passed
......@@ -9,6 +9,11 @@ and this project adheres to `Semantic Versioning`_.
Unreleased
----------
Added
~~~~~
* Periodic tasks can now have a default schedule, which is automatically created
Fixed
~~~~~
......
......@@ -17,7 +17,12 @@ from .registries import (
site_preferences_registry,
)
from .util.apps import AppConfig
from .util.core_helpers import get_or_create_favicon, get_site_preferences, has_person
from .util.core_helpers import (
create_default_celery_schedule,
get_or_create_favicon,
get_site_preferences,
has_person,
)
from .util.sass_helpers import clean_scss
......@@ -140,6 +145,9 @@ class CoreConfig(AppConfig):
for name, default in settings.DEFAULT_FAVICON_PATHS.items():
get_or_create_favicon(name, default, is_favicon=name == "favicon")
# Create default periodic tasks
create_default_celery_schedule()
def user_logged_in(
self, sender: type, request: Optional[HttpRequest], user: "User", **kwargs
) -> None:
......
from datetime import timedelta
from django.conf import settings
from django.core import management
......@@ -15,7 +17,7 @@ def send_notification(notification: int, resend: bool = False) -> None:
_send_notification(notification, resend)
@app.task
@app.task(run_every=timedelta(days=1))
def backup_data() -> None:
"""Backup database and media using django-dbbackup."""
# Assemble command-line options for dbbackup management command
......
......@@ -332,3 +332,60 @@ def process_custom_context_processors(context_processors: list) -> Dict[str, Any
for processor in processors:
context.update(processor(None))
return context
def create_default_celery_schedule():
"""Create default periodic tasks in database for tasks that have a schedule defined."""
from celery import current_app
from celery.schedules import BaseSchedule, crontab, schedule, solar
from django_celery_beat.clockedschedule import clocked
from django_celery_beat.models import (
ClockedSchedule,
CrontabSchedule,
IntervalSchedule,
PeriodicTask,
SolarSchedule,
)
defined_periodic_tasks = PeriodicTask.objects.values_list("task", flat=True).all()
for name, task in current_app.tasks.items():
if name in defined_periodic_tasks:
# Task is already known in database, skip
continue
run_every = getattr(task, "run_every", None)
if not run_every:
# Task has no default schedule, skip
continue
if isinstance(run_every, (float, int, timedelta)):
# Schedule is defined as a raw seconds value or timedelta, convert to schedule class
run_every = schedule(run_every)
elif not isinstance(run_every, BaseSchedule):
raise ValueError(f"Task {name} has an invalid schedule defined.")
# Find matching django-celery-beat schedule model
if isinstance(run_every, clocked):
Schedule = ClockedSchedule
attr = "clocked"
elif isinstance(run_every, crontab):
Schedule = CrontabSchedule
attr = "crontab"
elif isinstance(run_every, schedule):
Schedule = IntervalSchedule
attr = "interval"
elif isinstance(run_every, solar):
Schedule = SolarSchedule
attr = "solar"
else:
raise ValueError(f"Task {name} has an unknown schedule class defined.")
# Get or create schedule in database
db_schedule = Schedule.from_schedule(run_every)
db_schedule.save()
# Create periodic task
PeriodicTask.objects.create(
name=f"{name} (default schedule)", task=name, **{attr: db_schedule}
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment