Skip to content

Commit

Permalink
Merge pull request #10 from anexia/cron_seconds
Browse files Browse the repository at this point in the history
Allow seconds in cron string settings
  • Loading branch information
nezhar authored Jul 24, 2024
2 parents 08d6a11 + 5dcbe8e commit 1156e17
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 31 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Support for seconds in cron-like tasks

### Removed

- Human readable cron name due to incompatibility of [cron-descriptor](https://github.com/Salamek/cron-descriptor) and [croniter](https://github.com/kiorky/croniter) for seconds
- `cron-descriptor` from requirements

## [1.1.2]

### Fixed
Expand Down
15 changes: 0 additions & 15 deletions django_future_tasks/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,34 +36,19 @@ class Media:
css = {"all": ("django_future_tasks/cronfield.css",)}


class FutureTaskInline(admin.TabularInline):
verbose_name = "Corresponding single task"
verbose_name_plural = "Corresponding single tasks"
model = FutureTask
fields = ["task_id", "eta", "status"]
readonly_fields = ["task_id", "eta", "status"]
extra = 0
classes = ["collapse"]
ordering = ["-eta"]
max_num = 100


@admin.register(PeriodicFutureTask)
class PeriodicFutureTaskAdmin(admin.ModelAdmin):
readonly_fields = [
"cron_humnan_readable",
"last_task_creation",
"next_planned_execution",
]
list_display = [
"periodic_task_id",
"cron_string",
"cron_humnan_readable",
"is_active",
"type",
"next_planned_execution",
]
list_editable = ["cron_string", "is_active"]
inlines = [FutureTaskInline]
list_filter = ["type", "is_active"]
form = PeriodicFutureTaskAdminForm
35 changes: 35 additions & 0 deletions django_future_tasks/fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import re

from cronfield.models import CronField
from django.core.exceptions import ValidationError


def _validate_CRON_string(value):
"""Validation routine for CRON string in TestingPlan"""

if value.strip() != value:
raise ValidationError("Leading nor trailing spaces are allowed")
columns = value.split()
if columns != value.split(" "):
raise ValidationError("Use only a single space as a column separator")

if len(columns) not in [5, 6]:
raise ValidationError("Entry has to consist of 5 or 6 columns")

pattern = r"^(\*|\d+(-\d+)?(,\d+(-\d+)?)*)(/\d+)?$"
p = re.compile(pattern)
for i, c in enumerate(columns):
if not p.match(c):
raise ValidationError("Incorrect value {} in column {}".format(c, i + 1))


class FutureTaskCronField(CronField):
def validate(self, value, model_instance):
super(CronField, self).validate(value, model_instance)
if self.editable: # Skip validation for non-editable fields.
_validate_CRON_string(value)

def __init__(self, *args, **kwargs):
kwargs["default"] = "* * * * * *"
kwargs["help_text"] = "Minute Hour Day Month Weekday Second"
super().__init__(*args, **kwargs)
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def handle_tick(self):
p_task.is_active = False
break

dt_format = "%Y-%m-%d %H:%M%z"
dt_format = "%Y-%m-%d %H:%M:%S%z"
task_id = f"{p_task.periodic_task_id} ({dt.strftime(dt_format)})"
FutureTask.objects.create(
task_id=task_id,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.14 on 2024-07-22 11:43

from django.db import migrations

import django_future_tasks.fields


class Migration(migrations.Migration):
dependencies = [
("django_future_tasks", "0006_periodicfuturetask_end_time"),
]

operations = [
migrations.AlterField(
model_name="periodicfuturetask",
name="cron_string",
field=django_future_tasks.fields.FutureTaskCronField(
default="* * * * * *",
help_text="Minute Hour Day Month Weekday Second",
max_length=100,
),
),
]
14 changes: 3 additions & 11 deletions django_future_tasks/models.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import datetime

import croniter
from cron_descriptor import CasingTypeEnum, ExpressionDescriptor
from cronfield.models import CronField
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import models
Expand All @@ -11,6 +9,8 @@
from django.utils.dateformat import format
from django.utils.translation import gettext_lazy as _

from .fields import FutureTaskCronField


class FutureTask(models.Model):
FUTURE_TASK_STATUS_OPEN = "open"
Expand Down Expand Up @@ -77,7 +77,7 @@ class PeriodicFutureTask(models.Model):
blank=True,
null=True,
)
cron_string = CronField()
cron_string = FutureTaskCronField()
is_active = models.BooleanField(_("Active"), default=True)
max_number_of_executions = models.IntegerField(
_("Maximal number of executions"), null=True, blank=True
Expand Down Expand Up @@ -115,14 +115,6 @@ def next_planned_execution(self):
settings.DATETIME_FORMAT,
)

def cron_humnan_readable(self):
descriptor = ExpressionDescriptor(
expression=self.cron_string,
casing_type=CasingTypeEnum.Sentence,
use_24hour_time_format=False,
)
return descriptor.get_description()

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__original_is_active = self.is_active
Expand Down
3 changes: 1 addition & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ coverage>=7.2.3,<7.3
pre-commit>=3.2.2,<3.3

# TestApp dependencies
django>=3.2,<4
django>=4.2,<5

# Cron
croniter>=1.4.1,<1.5
cron-descriptor>=1.4.0, <1.5
django-cronfield>=0.2.0,<0.3
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@

setup(
name="django-future-tasks",
version=os.getenv("PACKAGE_VERSION", "1.1.2").replace("refs/tags/", ""),
version=os.getenv("PACKAGE_VERSION", "1.2.0").replace("refs/tags/", ""),
packages=find_packages(),
include_package_data=True,
install_requires=[
"croniter>=1.4.1,<1.5",
"cron-descriptor>=1.4.0,<1.5",
"django-cronfield>=0.2.0,<0.3",
],
license="MIT License",
Expand Down

0 comments on commit 1156e17

Please sign in to comment.