Skip to content

Commit

Permalink
Merge branch 'master' into support-windows
Browse files Browse the repository at this point in the history
  • Loading branch information
olivierdalang authored Feb 13, 2024
2 parents b371f27 + 9be62ee commit 88cbb2a
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 10 deletions.
4 changes: 4 additions & 0 deletions django_toosimple_q/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ def last_due_(self, obj):

@admin.display()
def next_due_(self, obj):
# for schedule not in the code anymore
if not obj.schedule:
return "invalid"

if len(obj.past_dues) >= 1:
next_due = obj.past_dues[0]
else:
Expand Down
9 changes: 5 additions & 4 deletions django_toosimple_q/management/commands/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging
import os
import signal
from time import sleep
from traceback import format_exc

from django.core.management.base import BaseCommand, CommandError
Expand Down Expand Up @@ -65,10 +66,10 @@ def add_arguments(self, parser):
def handle(self, *args, **options):
# Handle interuption signals
signal.signal(signal.SIGINT, self.handle_signal)
# signal.signal(signal.SIGTERM, self.handle_signal)
signal.signal(signal.SIGTERM, signal.default_int_handler)
# for simulating an exception in tests
signal.signal(signal.SIGTERM, self.handle_signal)
# Custom signal to provoke an artifical exception, used for testing only
if hasattr(signal, "SIGUSR1"):
# this doesn't exist on Windows
signal.signal(signal.SIGUSR1, self.handle_signal)

# TODO: replace by simple-parsing
Expand Down Expand Up @@ -243,7 +244,7 @@ def do_loop(self) -> bool:
logger.debug(f"Waiting for next tick...")
next_run = last_run + datetime.timedelta(seconds=self.tick_duration)
while not self.exit_requested and now() < next_run:
pass
sleep(1)

return True

Expand Down
4 changes: 4 additions & 0 deletions django_toosimple_q/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ def icon(self):

@cached_property
def past_dues(self):
if self.schedule is None:
# Deal with invalid schedule (e.g. deleted from the code but still in the DB)
return []

if self.schedule.cron == "manual":
# A manual schedule is never due
return []
Expand Down
5 changes: 1 addition & 4 deletions django_toosimple_q/schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from typing import Dict, List, Optional

from .logging import logger
from .registry import tasks_registry
from .task import Task


Expand Down Expand Up @@ -42,9 +41,7 @@ def execute(self, dues: List[Optional[datetime]]):
if self.datetime_kwarg:
dt_kwarg = {self.datetime_kwarg: due}

tasks_registry[self.name].enqueue(
*self.args, due=due, **dt_kwarg, **self.kwargs
)
self.task.enqueue(*self.args, due=due, **dt_kwarg, **self.kwargs)

def __str__(self):
return f"Schedule {self.name}"
37 changes: 35 additions & 2 deletions django_toosimple_q/tests/tests_regression.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import time

from django.core import management

from django_toosimple_q.decorators import register_task, schedule_task
from django_toosimple_q.models import TaskExec
from django_toosimple_q.registry import schedules_registry, tasks_registry

from .base import TooSimpleQBackgroundTestCase
from .base import TooSimpleQBackgroundTestCase, TooSimpleQRegularTestCase


class TestRegression(TooSimpleQBackgroundTestCase):
class TestRegressionBackground(TooSimpleQBackgroundTestCase):
def test_regr_schedule_short(self):
# Regression test for an issue where a schedule with smaller periods was not always processed

Expand All @@ -17,3 +21,32 @@ def test_regr_schedule_short(self):

# It should do almost 20 tasks
self.assertGreaterEqual(TaskExec.objects.all().count(), 18)


class TestRegressionRegular(TooSimpleQRegularTestCase):
def test_deleting_schedule(self):
# Regression test for an issue where deleting a schedule in code would crash the admin view

@schedule_task(cron="0 12 * * *", datetime_kwarg="scheduled_on")
@register_task(name="normal")
def a(scheduled_on):
return f"{scheduled_on:%Y-%m-%d %H:%M}"

management.call_command("worker", "--until_done")

schedules_registry.clear()
tasks_registry.clear()

# the admin view still works even for deleted schedules
response = self.client.get("/admin/toosimpleq/scheduleexec/")
self.assertEqual(response.status_code, 200)

def test_different_schedule_and_task(self):
# Regression test for an issue where schedule with a different name than the task would fail

@schedule_task(cron="0 12 * * *", name="name_a", run_on_creation=True)
@register_task(name="name_b")
def a():
return True

management.call_command("worker", "--until_done")

0 comments on commit 88cbb2a

Please sign in to comment.