Skip to content

Commit

Permalink
feat: ensure the Routine.attempt_count is always less or equal to max…
Browse files Browse the repository at this point in the history
…_retries
  • Loading branch information
lucasgomide authored and joaodaher committed Jul 13, 2023
1 parent e7a7a25 commit f3ff6e3
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.2.1 on 2023-07-12 22:34

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("django_cloud_tasks", "0002_alter_routine_status_alter_routine_task_name"),
]

operations = [
migrations.AlterField(
model_name="routine",
name="max_retries",
field=models.PositiveIntegerField(default=20),
),
migrations.AddConstraint(
model_name="routine",
constraint=models.CheckConstraint(
check=models.Q(("max_retries__gte", models.F("attempt_count"))),
name="max_retries_less_than_attempt_count",
),
),
]
10 changes: 9 additions & 1 deletion django_cloud_tasks/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class Statuses(models.TextChoices):
encoder=serializers.JSONEncoder,
)
attempt_count = models.PositiveIntegerField(default=0)
max_retries = models.PositiveIntegerField(null=True)
max_retries = models.PositiveIntegerField(default=20)
output = models.JSONField(
null=True,
blank=True,
Expand All @@ -77,6 +77,14 @@ class Statuses(models.TextChoices):
related_name="dependent_routines",
)

class Meta:
constraints = (
models.CheckConstraint(
name="max_retries_less_than_attempt_count",
check=models.Q(max_retries__gte=models.F("attempt_count")),
),
)

def fail(self, output: dict) -> None:
self.output = output
self.status = self.Statuses.FAILED
Expand Down
2 changes: 1 addition & 1 deletion django_cloud_tasks/tasks/routine_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def process_routine(self, routine: models.Routine):
logger.info(f"Routine #{routine.pk} is already completed")
return

if routine.max_retries and routine.attempt_count >= routine.max_retries:
if routine.attempt_count >= routine.max_retries:
error_message = f"Routine #{routine.pk} has exhausted retries and is being reverted"
logger.info(error_message)
routine.fail(output={"error": error_message})
Expand Down
8 changes: 7 additions & 1 deletion sample_project/sample_app/tests/tests_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.test import TestCase
from django.utils import timezone
from freezegun import freeze_time

from django.db import IntegrityError
from django_cloud_tasks import models
from django_cloud_tasks.tests import factories

Expand Down Expand Up @@ -145,6 +145,12 @@ def test_add_next(self):
self.assertEqual(expected_routine_1["body"], next_routine.body)
self.assertEqual(expected_routine_1["task_name"], next_routine.task_name)

def test_ensure_max_retries_greater_than_attempt_count(self):
with self.assertRaisesRegex(
expected_exception=IntegrityError, expected_regex="constraint failed: max_retries_less_than_attempt_count"
):
factories.RoutineFactory(max_retries=1, attempt_count=5)


class PipelineModelTest(TestCase):
def test_start_pipeline(self):
Expand Down

0 comments on commit f3ff6e3

Please sign in to comment.