Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion src/task_processor/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,23 @@ def should_execute(self) -> bool:
# If we have never run this task, then we should execute it only if
# the time has passed after which we want to ensure this task runs.
# This allows us to control when intensive tasks should be run.
return not (self.first_run_time and self.first_run_time > now.time())
if not self.first_run_time:
return True
first_run_today = now.replace(
hour=self.first_run_time.hour,
minute=self.first_run_time.minute,
second=self.first_run_time.second,
microsecond=self.first_run_time.microsecond,
)
# Handle midnight boundary using 12-hour window heuristic.
time_difference = (now - first_run_today).total_seconds()
if time_difference > 12 * 3600:
# first_run_today appears far in the past; it refers to tomorrow.
return False
if time_difference < -12 * 3600:
# first_run_today appears far in the future; it refers to yesterday.
return True
return now >= first_run_today

# if the last run was at t- run_every, then we should execute it
if (timezone.now() - last_task_run.started_at) >= self.run_every:
Expand Down
29 changes: 29 additions & 0 deletions tests/unit/task_processor/test_unit_task_processor_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import pytest
from django.utils import timezone
from freezegun import freeze_time
from pytest_mock import MockerFixture

from task_processor.decorators import register_task_handler
Expand Down Expand Up @@ -80,3 +81,31 @@ def test_recurring_task_run_should_execute_first_run_at(
).should_execute
== expected
)


@freeze_time("2026-01-15 23:05:23")
def test_recurring_task_should_execute__first_run_time_after_midnight__returns_false() -> (
None
):
# Given
task = RecurringTask(
first_run_time=time(0, 5, 23),
run_every=timedelta(days=1),
)

# When & Then
assert task.should_execute is False


@freeze_time("2026-01-16 00:30:00")
def test_recurring_task_should_execute__first_run_time_before_midnight__returns_true() -> (
None
):
# Given
task = RecurringTask(
first_run_time=time(23, 0, 0),
run_every=timedelta(days=1),
)

# When & Then
assert task.should_execute is True