Skip to content

Commit 5be1aab

Browse files
committed
Tweaks
1 parent c0b11e7 commit 5be1aab

File tree

6 files changed

+72
-42
lines changed

6 files changed

+72
-42
lines changed

django_tasks/backends/database/apps.py

+3
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ class TasksAppConfig(AppConfig):
55
name = "django_tasks.backends.database"
66
label = "django_tasks_database"
77
verbose_name = "Tasks Database Backend"
8+
9+
def ready(self) -> None:
10+
from . import signal_handlers # noqa

django_tasks/backends/database/backend.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def _task_to_db_task(
4444
priority=task.priority,
4545
task_path=task.module_path,
4646
queue_name=task.queue_name,
47-
run_after=task.run_after,
47+
run_after=task.run_after, # type: ignore[misc]
4848
backend_name=self.alias,
4949
)
5050

Original file line numberDiff line numberDiff line change
@@ -1,45 +1,70 @@
1-
# Generated by Django 5.1.4 on 2025-04-28 11:28
1+
# Generated by Django 5.1.5 on 2025-05-02 12:05
22

33
import datetime
4+
45
from django.db import migrations, models
56

67

78
class Migration(migrations.Migration):
8-
99
dependencies = [
10-
('django_tasks_database', '0015_correctly_order_run_after'),
10+
("django_tasks_database", "0015_correctly_order_run_after"),
1111
]
1212

1313
operations = [
1414
migrations.AlterModelOptions(
15-
name='dbtaskresult',
16-
options={'ordering': [models.OrderBy(models.F('priority'), descending=True), models.OrderBy(models.F('run_after'))], 'verbose_name': 'Task Result', 'verbose_name_plural': 'Task Results'},
15+
name="dbtaskresult",
16+
options={
17+
"ordering": [
18+
models.OrderBy(models.F("priority"), descending=True),
19+
models.OrderBy(models.F("run_after")),
20+
],
21+
"verbose_name": "Task Result",
22+
"verbose_name_plural": "Task Results",
23+
},
1724
),
1825
migrations.AlterField(
19-
model_name='dbtaskresult',
20-
name='backend_name',
21-
field=models.CharField(max_length=32, verbose_name='backend name'),
26+
model_name="dbtaskresult",
27+
name="backend_name",
28+
field=models.CharField(max_length=32, verbose_name="backend name"),
2229
),
2330
migrations.AlterField(
24-
model_name='dbtaskresult',
25-
name='queue_name',
26-
field=models.CharField(default='default', max_length=32, verbose_name='queue name'),
31+
model_name="dbtaskresult",
32+
name="queue_name",
33+
field=models.CharField(
34+
default="default", max_length=32, verbose_name="queue name"
35+
),
2736
),
2837
migrations.AlterField(
29-
model_name='dbtaskresult',
30-
name='run_after',
31-
field=models.DateTimeField(default=datetime.datetime(9999, 1, 1, 0, 0, tzinfo=datetime.timezone.utc), verbose_name='run after'),
38+
model_name="dbtaskresult",
39+
name="run_after",
40+
field=models.DateTimeField(
41+
default=datetime.datetime(
42+
9999, 12, 2, 5, 59, 59, 999999, tzinfo=datetime.timezone.utc
43+
),
44+
verbose_name="run after",
45+
),
46+
preserve_default=False,
3247
),
3348
migrations.AddIndex(
34-
model_name='dbtaskresult',
35-
index=models.Index(models.F('status'), models.OrderBy(models.F('priority'), descending=True), models.OrderBy(models.F('run_after')), condition=models.Q(('status', 'NEW')), name='django_task_new_ordering_idx'),
49+
model_name="dbtaskresult",
50+
index=models.Index(
51+
models.F("status"),
52+
models.OrderBy(models.F("priority"), descending=True),
53+
models.OrderBy(models.F("run_after")),
54+
condition=models.Q(("status", "NEW")),
55+
name="django_task_new_ordering_idx",
56+
),
3657
),
3758
migrations.AddIndex(
38-
model_name='dbtaskresult',
39-
index=models.Index(fields=['queue_name'], name='django_task_queue_n_99c321_idx'),
59+
model_name="dbtaskresult",
60+
index=models.Index(
61+
fields=["queue_name"], name="django_task_queue_n_99c321_idx"
62+
),
4063
),
4164
migrations.AddIndex(
42-
model_name='dbtaskresult',
43-
index=models.Index(fields=['backend_name'], name='django_task_backend_071754_idx'),
65+
model_name="dbtaskresult",
66+
index=models.Index(
67+
fields=["backend_name"], name="django_task_backend_071754_idx"
68+
),
4469
),
4570
]

django_tasks/backends/database/models.py

+5-12
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def __class_getitem__(cls, _):
4747
return cls
4848

4949

50-
DATE_MAX = datetime.datetime(9999, 1, 1, tzinfo=datetime.timezone.utc)
50+
DATE_MAX = datetime.datetime.max.replace(day=1).astimezone(datetime.timezone.utc)
5151

5252

5353
class DBTaskResultQuerySet(models.QuerySet):
@@ -104,7 +104,7 @@ class DBTaskResult(GenericBase[P, T], models.Model):
104104
)
105105
backend_name = models.CharField(_("backend name"), max_length=32)
106106

107-
run_after = models.DateTimeField(_("run after"), default=DATE_MAX)
107+
run_after = models.DateTimeField(_("run after"))
108108

109109
return_value = models.JSONField(_("return value"), default=None, null=True)
110110

@@ -119,7 +119,8 @@ class Meta:
119119
verbose_name_plural = _("Task Results")
120120
indexes = [
121121
models.Index(
122-
"status", *ordering,
122+
"status",
123+
*ordering,
123124
name="django_task_new_ordering_idx",
124125
condition=Q(status=ResultStatus.NEW),
125126
),
@@ -142,11 +143,6 @@ class Meta:
142143
)
143144
]
144145

145-
def save(self, **kwargs):
146-
if self.run_after is None:
147-
self.run_after = DATE_MAX
148-
super().save(**kwargs)
149-
150146
@property
151147
def task(self) -> Task[P, T]:
152148
task = import_string(self.task_path)
@@ -156,13 +152,10 @@ def task(self) -> Task[P, T]:
156152
f"Task {self.id} does not point to a Task ({self.task_path})"
157153
)
158154

159-
if self.run_after == DATE_MAX:
160-
self.run_after = None
161-
162155
return task.using(
163156
priority=self.priority,
164157
queue_name=self.queue_name,
165-
run_after=self.run_after,
158+
run_after=None if self.run_after == DATE_MAX else self.run_after,
166159
backend=self.backend_name,
167160
)
168161

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from typing import Any
2+
3+
from django.db.models.signals import pre_save
4+
from django.dispatch import receiver
5+
6+
from .models import DATE_MAX, DBTaskResult
7+
8+
9+
@receiver(pre_save, sender=DBTaskResult)
10+
def set_run_after(sender: Any, instance: DBTaskResult, **kwargs: Any) -> None:
11+
if instance.run_after is None:
12+
instance.run_after = DATE_MAX

tests/tests/test_database_backend.py

+6-9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import copy
12
import json
23
import logging
34
import os
@@ -389,15 +390,11 @@ def test_enqueue_logs(self) -> None:
389390

390391
def test_index_scan_for_ready(self) -> None:
391392
test_tasks.noop_task.enqueue()
392-
db_task = DBTaskResult.objects.first()
393-
new_db_tasks = []
394-
for _ in range(5000):
395-
new_db_task = DBTaskResult()
396-
for f in DBTaskResult._meta.fields:
397-
if f.name != "id":
398-
setattr(new_db_task, f.attname, getattr(db_task, f.attname))
399-
new_db_tasks.append(new_db_task)
400-
DBTaskResult.objects.bulk_create(new_db_tasks)
393+
394+
# Quickly duplicate tasks
395+
db_task = DBTaskResult.objects.get()
396+
db_task.id = None
397+
DBTaskResult.objects.bulk_create([copy.copy(db_task) for _ in range(5000)])
401398

402399
# Update query plan for certain databases
403400
if connection.vendor == "postgresql":

0 commit comments

Comments
 (0)