Skip to content

Commit bf6f0ee

Browse files
committed
wip
1 parent ed13130 commit bf6f0ee

File tree

13 files changed

+611
-49
lines changed

13 files changed

+611
-49
lines changed

docs/changelog.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# Changelog
22

3+
4+
## v2.2.0 🌈
5+
6+
### 🚀 Features
7+
8+
- Created a new `Task` model representing all kind of scheduled tasks.
9+
- In future versions, `CronTask`, `ScheduledTask` and `RepeatableTask` will be removed.
10+
- `Task` model has a `task_type` field to differentiate between the types of tasks.
11+
- Old tasks in the database will be migrated to the new `Task` model automatically.
12+
13+
314
## v2.1.0 🌈
415

516
### 🚀 Features

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ name = "django-tasks-scheduler"
77
packages = [
88
{ include = "scheduler" },
99
]
10-
version = "2.1.0"
10+
version = "2.2.0"
1111
description = "An async job scheduler for django using redis"
1212
readme = "README.md"
1313
keywords = ["redis", "django", "background-jobs", "job-queue", "task-queue", "redis-queue", "scheduled-jobs"]

scheduler/management/commands/import.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from django.utils import timezone
1010

1111
from scheduler.models import TaskArg, TaskKwarg, Task
12+
from scheduler.models.task import TaskType
1213
from scheduler.tools import MODEL_NAMES
1314

1415

@@ -17,16 +18,16 @@ def job_model_str(model_str: str) -> str:
1718
return model_str[:-3] + "Task"
1819
return model_str
1920

20-
def get_task_type(model_str: str) -> Task.TaskType:
21+
def get_task_type(model_str: str) -> TaskType:
2122
model_str = job_model_str(model_str)
2223
if model_str not in MODEL_NAMES:
2324
raise ValueError(f"Invalid model {model_str}")
2425
if model_str == "CronTask":
25-
return Task.TaskType.CRON
26+
return TaskType.CRON
2627
elif model_str == "RepeatableTask":
27-
return Task.TaskType.REPEATABLE
28+
return TaskType.REPEATABLE
2829
elif model_str == "ScheduledTask":
29-
return Task.TaskType.ONCE
30+
return TaskType.ONCE
3031

3132
def create_task_from_dict(task_dict: Dict[str, Any], update):
3233
existing_job = Task.objects.filter(name=task_dict["name"]).first()

scheduler/models/scheduled_task.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def get_queue_choices():
7070
class BaseTask(models.Model):
7171
created = models.DateTimeField(auto_now_add=True)
7272
modified = models.DateTimeField(auto_now=True)
73-
TASK_TYPE = "BaseTask"
73+
task_type = "BaseTask"
7474
name = models.CharField(
7575
_("name"),
7676
max_length=128,
@@ -180,7 +180,7 @@ def _enqueue_args(self) -> Dict:
180180
"""
181181
res = dict(
182182
meta=dict(
183-
task_type=self.TASK_TYPE,
183+
task_type=self.task_type,
184184
scheduled_task_id=self.id,
185185
),
186186
on_success=success_callback,
@@ -227,7 +227,7 @@ def schedule(self) -> bool:
227227
job = self.rqueue.enqueue_at(
228228
schedule_time,
229229
tools.run_task,
230-
args=(self.TASK_TYPE, self.id),
230+
args=(self.task_type, self.id),
231231
**kwargs,
232232
)
233233
self.job_id = job.id
@@ -239,7 +239,7 @@ def enqueue_to_run(self) -> bool:
239239
kwargs = self._enqueue_args()
240240
job = self.rqueue.enqueue(
241241
tools.run_task,
242-
args=(self.TASK_TYPE, self.id),
242+
args=(self.task_type, self.id),
243243
**kwargs,
244244
)
245245
self.job_id = job.id
@@ -266,7 +266,7 @@ def _schedule_time(self):
266266
def to_dict(self) -> Dict:
267267
"""Export model to dictionary, so it can be saved as external file backup"""
268268
res = dict(
269-
model=self.TASK_TYPE,
269+
model=self.task_type,
270270
name=self.name,
271271
callable=self.callable,
272272
callable_args=[
@@ -312,7 +312,7 @@ def get_absolute_url(self):
312312

313313
def __str__(self):
314314
func = self.function_string()
315-
return f"{self.TASK_TYPE}[{self.name}={func}]"
315+
return f"{self.task_type}[{self.name}={func}]"
316316

317317
def save(self, **kwargs):
318318
schedule_job = kwargs.pop("schedule_job", True)
@@ -391,7 +391,7 @@ class Meta:
391391

392392

393393
class ScheduledTask(ScheduledTimeMixin, BaseTask):
394-
TASK_TYPE = "ScheduledTask"
394+
task_type = "ScheduledTask"
395395

396396
def ready_for_schedule(self) -> bool:
397397
return super(ScheduledTask, self).ready_for_schedule() and (
@@ -405,6 +405,7 @@ class Meta:
405405

406406

407407
class RepeatableTask(RepeatableMixin, ScheduledTimeMixin, BaseTask):
408+
task_type = "RepeatableTask"
408409
class TimeUnits(models.TextChoices):
409410
SECONDS = "seconds", _("seconds")
410411
MINUTES = "minutes", _("minutes")
@@ -422,7 +423,6 @@ class TimeUnits(models.TextChoices):
422423
null=True,
423424
help_text=_("Number of times to run the job. Leaving this blank means it will run forever."),
424425
)
425-
TASK_TYPE = "RepeatableTask"
426426

427427
def clean(self):
428428
super(RepeatableTask, self).clean()
@@ -497,7 +497,7 @@ class Meta:
497497

498498

499499
class CronTask(RepeatableMixin, BaseTask):
500-
TASK_TYPE = "CronTask"
500+
task_type = "CronTask"
501501

502502
cron_string = models.CharField(
503503
_("cron string"),

scheduler/models/task.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,12 @@ def get_queue_choices():
6464
return [(queue, queue) for queue in QUEUES.keys()]
6565

6666

67-
class Task(models.Model):
68-
class TaskType(models.TextChoices):
69-
CRON = "CronTask", _("Cron Task")
70-
REPEATABLE = "RepeatableTask", _("Repeatable Task")
71-
ONCE = "OnceTask", _("Run once")
67+
class TaskType(models.TextChoices):
68+
CRON = "CronTask", _("Cron Task")
69+
REPEATABLE = "RepeatableTask", _("Repeatable Task")
70+
ONCE = "OnceTask", _("Run once")
7271

72+
class Task(models.Model):
7373
class TimeUnits(models.TextChoices):
7474
SECONDS = "seconds", _("seconds")
7575
MINUTES = "minutes", _("minutes")
@@ -243,7 +243,7 @@ def _enqueue_args(self) -> Dict:
243243
res["job_timeout"] = self.timeout
244244
if self.result_ttl is not None:
245245
res["result_ttl"] = self.result_ttl
246-
if self.task_type == self.TaskType.REPEATABLE:
246+
if self.task_type == TaskType.REPEATABLE:
247247
res["meta"]["interval"] = self.interval_seconds()
248248
res["meta"]["repeat"] = self.repeat
249249
return res
@@ -267,7 +267,7 @@ def ready_for_schedule(self) -> bool:
267267
if not self.enabled:
268268
logger.debug(f"Task {str(self)} disabled, enable task before scheduling")
269269
return False
270-
if self.task_type == Task.TaskType.REPEATABLE and self._schedule_time() < timezone.now():
270+
if self.task_type == TaskType.REPEATABLE and self._schedule_time() < timezone.now():
271271
return False
272272
return True
273273

@@ -316,9 +316,9 @@ def unschedule(self) -> bool:
316316
return True
317317

318318
def _schedule_time(self):
319-
if self.task_type == self.TaskType.CRON:
319+
if self.task_type == TaskType.CRON:
320320
self.scheduled_time = tools.get_next_cron_time(self.cron_string)
321-
elif self.task_type == self.TaskType.REPEATABLE:
321+
elif self.task_type == TaskType.REPEATABLE:
322322
_now = timezone.now()
323323
if self.scheduled_time >= _now:
324324
return utc(self.scheduled_time) if django_settings.USE_TZ else self.scheduled_time
@@ -458,8 +458,8 @@ def clean_cron_string(self):
458458
def clean(self):
459459
self.clean_queue()
460460
self.clean_callable()
461-
if self.task_type == self.TaskType.CRON:
461+
if self.task_type == TaskType.CRON:
462462
self.clean_cron_string()
463-
if self.task_type == self.TaskType.REPEATABLE:
463+
if self.task_type == TaskType.REPEATABLE:
464464
self.clean_interval_unit()
465465
self.clean_result_ttl()

scheduler/tests/test_cron_task.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from scheduler import settings
44
from scheduler.models import CronTask
55
from scheduler.tools import create_worker
6-
from .test_models import BaseTestCases
6+
from .test_old_models import BaseTestCases
77
from .testtools import task_factory
88
from ..queues import get_queue
99

scheduler/tests/test_internals.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
class TestInternals(SchedulerBaseCase):
1111
def test_get_scheduled_job(self):
1212
task = task_factory(ScheduledTask, scheduled_time=timezone.now() - timedelta(hours=1))
13-
self.assertEqual(task, get_scheduled_task(task.TASK_TYPE, task.id))
13+
self.assertEqual(task, get_scheduled_task(task.task_type, task.id))
1414
with self.assertRaises(ValueError):
15-
get_scheduled_task(task.TASK_TYPE, task.id + 1)
15+
get_scheduled_task(task.task_type, task.id + 1)
1616
with self.assertRaises(ValueError):
1717
get_scheduled_task("UNKNOWN_JOBTYPE", task.id)

scheduler/tests/test_mgmt_cmds.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
from django.core.management import call_command
88
from django.test import TestCase
99

10-
from scheduler.models import ScheduledTask, RepeatableTask
10+
from scheduler.models import ScheduledTask, RepeatableTask, Task
1111
from scheduler.queues import get_queue
1212
from scheduler.tests.jobs import failing_job, test_job
1313
from scheduler.tests.testtools import task_factory
1414
from . import test_settings # noqa
1515
from .test_views import BaseTestCase
16+
from ..models.task import TaskType
1617
from ..tools import create_worker
1718

1819

@@ -231,8 +232,8 @@ def test_import__should_schedule_job(self):
231232
# act
232233
call_command("import", filename=self.tmpfile.name)
233234
# assert
234-
self.assertEqual(1, ScheduledTask.objects.count())
235-
db_job = ScheduledTask.objects.first()
235+
self.assertEqual(1, Task.objects.filter(task_type=TaskType.ONCE).count())
236+
db_job = Task.objects.filter(task_type=TaskType.ONCE).first()
236237
attrs = ["name", "queue", "callable", "enabled", "timeout"]
237238
for attr in attrs:
238239
self.assertEqual(getattr(jobs[0], attr), getattr(db_job, attr))
@@ -247,8 +248,8 @@ def test_import__should_schedule_job_yaml(self):
247248
# act
248249
call_command("import", filename=self.tmpfile.name, format="yaml")
249250
# assert
250-
self.assertEqual(1, ScheduledTask.objects.count())
251-
db_job = ScheduledTask.objects.first()
251+
self.assertEqual(1, Task.objects.filter(task_type=TaskType.ONCE).count())
252+
db_job = Task.objects.filter(task_type=TaskType.ONCE).objects.first()
252253
attrs = ["name", "queue", "callable", "enabled", "timeout"]
253254
for attr in attrs:
254255
self.assertEqual(getattr(jobs[0], attr), getattr(db_job, attr))
@@ -282,13 +283,13 @@ def test_import__should_schedule_job_reset(self):
282283
reset=True,
283284
)
284285
# assert
285-
self.assertEqual(1, ScheduledTask.objects.count())
286-
db_job = ScheduledTask.objects.first()
286+
self.assertEqual(1, Task.objects.filter(task_type=TaskType.ONCE).count())
287+
db_job = Task.objects.filter(task_type=TaskType.ONCE).first()
287288
attrs = ["name", "queue", "callable", "enabled", "timeout"]
288289
for attr in attrs:
289290
self.assertEqual(getattr(jobs[0], attr), getattr(db_job, attr))
290-
self.assertEqual(1, RepeatableTask.objects.count())
291-
db_job = RepeatableTask.objects.first()
291+
self.assertEqual(1, Task.objects.filter(task_type=TaskType.REPEATABLE).count())
292+
db_job = Task.objects.filter(task_type=TaskType.REPEATABLE).first()
292293
attrs = ["name", "queue", "callable", "enabled", "timeout"]
293294
for attr in attrs:
294295
self.assertEqual(getattr(jobs[1], attr), getattr(db_job, attr))
@@ -307,8 +308,8 @@ def test_import__should_schedule_job_update_existing(self):
307308
update=True,
308309
)
309310
# assert
310-
self.assertEqual(2, ScheduledTask.objects.count())
311-
db_job = ScheduledTask.objects.get(name=jobs[0].name)
311+
self.assertEqual(2, Task.objects.filter(task_type=TaskType.ONCE).count())
312+
db_job = Task.objects.filter(task_type=TaskType.ONCE).get(name=jobs[0].name)
312313
self.assertNotEqual(jobs[0].id, db_job.id)
313314
attrs = ["name", "queue", "callable", "enabled", "timeout"]
314315
for attr in attrs:
@@ -327,8 +328,8 @@ def test_import__should_schedule_job_without_update_existing(self):
327328
filename=self.tmpfile.name,
328329
)
329330
# assert
330-
self.assertEqual(2, ScheduledTask.objects.count())
331-
db_job = ScheduledTask.objects.get(name=jobs[0].name)
331+
self.assertEqual(2, Task.objects.filter(task_type=TaskType.ONCE).count())
332+
db_job = Task.objects.get(name=jobs[0].name)
332333
attrs = ["id", "name", "queue", "callable", "enabled", "timeout"]
333334
for attr in attrs:
334335
self.assertEqual(getattr(jobs[0], attr), getattr(db_job, attr))

scheduler/tests/test_models.py renamed to scheduler/tests/test_old_models.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -376,9 +376,7 @@ def test_admin_change_view__bad_redis_connection(self):
376376
def test_admin_enqueue_job_now(self):
377377
# arrange
378378
self.client.login(username="admin", password="admin")
379-
task = task_factory(
380-
self.TaskModelClass,
381-
)
379+
task = task_factory(self.TaskModelClass)
382380
self.assertIsNotNone(task.job_id)
383381
self.assertTrue(task.is_scheduled())
384382
data = {
@@ -396,7 +394,7 @@ def test_admin_enqueue_job_now(self):
396394
self.assertEqual(200, res.status_code)
397395
entry = _get_job_from_scheduled_registry(task)
398396
task_model, scheduled_task_id = entry.args
399-
self.assertEqual(task_model, task.TASK_TYPE)
397+
self.assertEqual(task_model, task.task_type)
400398
self.assertEqual(scheduled_task_id, task.id)
401399
self.assertEqual("scheduled", entry.get_status())
402400
assert_has_execution_with_status(task, "queued")
@@ -410,7 +408,7 @@ def test_admin_enqueue_job_now(self):
410408

411409
# assert 2
412410
entry = _get_job_from_scheduled_registry(task)
413-
self.assertEqual(task_model, task.TASK_TYPE)
411+
self.assertEqual(task_model, task.task_type)
414412
self.assertEqual(scheduled_task_id, task.id)
415413
assert_has_execution_with_status(task, "finished")
416414

scheduler/tests/test_repeatable_task.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from scheduler import settings
88
from scheduler.models import RepeatableTask
9-
from scheduler.tests.test_models import BaseTestCases
9+
from scheduler.tests.test_old_models import BaseTestCases
1010
from .testtools import task_factory, _get_job_from_scheduled_registry
1111

1212

0 commit comments

Comments
 (0)