Skip to content

Commit ebe13de

Browse files
authored
Merge pull request #1124 from tcely/patch-16
Begin a common task history model
2 parents 471853b + 4ac1d79 commit ebe13de

File tree

4 files changed

+132
-0
lines changed

4 files changed

+132
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Generated by Django 5.2.3 on 2025-06-30 07:11
2+
3+
import common.json
4+
import django.utils.timezone
5+
from django.db import migrations, models
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
initial = True
11+
12+
dependencies = [
13+
]
14+
15+
operations = [
16+
migrations.CreateModel(
17+
name='TaskHistory',
18+
fields=[
19+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20+
('name', models.CharField(db_index=True, max_length=190)),
21+
('task_id', models.CharField(db_index=True, max_length=40)),
22+
('task_params', models.JSONField(default=dict, encoder=common.json.JSONEncoder)),
23+
('verbose_name', models.CharField(blank=True, max_length=255, null=True)),
24+
('start_at', models.DateTimeField(blank=True, db_index=True, null=True)),
25+
('end_at', models.DateTimeField(db_index=True, default=django.utils.timezone.now)),
26+
('priority', models.IntegerField(db_index=True, default=0)),
27+
('queue', models.CharField(blank=True, db_index=True, max_length=190, null=True)),
28+
('attempts', models.IntegerField(db_index=True, default=0)),
29+
('failed_at', models.DateTimeField(blank=True, db_index=True, null=True)),
30+
('last_error', models.TextField(blank=True)),
31+
('repeat', models.BigIntegerField(default=0)),
32+
('repeat_until', models.DateTimeField(blank=True, null=True)),
33+
],
34+
),
35+
]
36+
37+

tubesync/common/models.py

Whitespace-only changes.

tubesync/common/models/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from .tasks import TaskHistory
2+
3+
__all__ = [
4+
'TaskHistory',
5+
]

tubesync/common/models/tasks.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
from datetime import timedelta
2+
3+
from django.db import models
4+
from django.utils import timezone
5+
6+
from ..json import JSONEncoder
7+
# from common.json import JSONEncoder
8+
9+
class TaskHistoryQuerySet(models.QuerySet):
10+
11+
def failed(self, within=None):
12+
"""
13+
:param within: A timedelta object
14+
:return: A queryset of CompletedTasks that failed within the given timeframe (e.g. less than 1h ago)
15+
"""
16+
qs = self.filter(
17+
failed_at__isnull=False,
18+
)
19+
if within:
20+
if not isinstance(within, timedelta):
21+
within = timedelta(seconds=within)
22+
time_limit = timezone.now() - within
23+
qs = qs.filter(failed_at__gt=time_limit)
24+
return qs
25+
26+
def succeeded(self, within=None):
27+
"""
28+
:param within: A timedelta object
29+
:return: A queryset of CompletedTasks that completed successfully within the given timeframe
30+
(e.g. less than 1h ago)
31+
"""
32+
qs = self.filter(
33+
failed_at__isnull=True,
34+
)
35+
if within:
36+
if not isinstance(within, timedelta):
37+
within = timedelta(seconds=within)
38+
time_limit = timezone.now() - within
39+
qs = qs.filter(end_at__gt=time_limit)
40+
return qs
41+
42+
43+
class TaskHistory(models.Model):
44+
# the "name" of the task/function to be run
45+
name = models.CharField(max_length=190, db_index=True)
46+
task_id = models.CharField(max_length=40, db_index=True)
47+
# the json encoded parameters to pass to the task
48+
task_params = models.JSONField(default=dict, encoder=JSONEncoder)
49+
50+
verbose_name = models.CharField(max_length=255, null=True, blank=True)
51+
52+
start_at = models.DateTimeField(db_index=True, null=True, blank=True)
53+
# when the task was completed
54+
end_at = models.DateTimeField(default=timezone.now, db_index=True)
55+
56+
# what priority the task had
57+
priority = models.IntegerField(default=0, db_index=True)
58+
# the "name" of the queue this is to be run on
59+
queue = models.CharField(max_length=190, db_index=True, null=True, blank=True)
60+
61+
# how many times the task has been tried
62+
attempts = models.IntegerField(default=0, db_index=True)
63+
# when the task last failed
64+
failed_at = models.DateTimeField(db_index=True, null=True, blank=True)
65+
# details of the error that occurred
66+
last_error = models.TextField(blank=True)
67+
68+
repeat = models.BigIntegerField(default=0)
69+
repeat_until = models.DateTimeField(null=True, blank=True)
70+
71+
objects = TaskHistoryQuerySet.as_manager()
72+
73+
def save(self, *args, **kwargs):
74+
self.queue = self.queue or None
75+
self.verbose_name = self.verbose_name or None
76+
return super().save(*args, **kwargs)
77+
78+
def has_error(self):
79+
"""
80+
Check if the last_error field is empty.
81+
"""
82+
return bool(self.last_error)
83+
84+
def __str__(self):
85+
return u'{} - {}'.format(
86+
self.verbose_name or self.task_name,
87+
self.end_at,
88+
)
89+
90+

0 commit comments

Comments
 (0)