Skip to content

Commit 6cfa9a2

Browse files
committed
add a scheduled_at property to task
1 parent 66b8a9e commit 6cfa9a2

2 files changed

Lines changed: 52 additions & 0 deletions

File tree

tasktiger/task.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,18 @@ def time_last_queued(self) -> Optional[datetime.datetime]:
183183
else:
184184
return datetime.datetime.utcfromtimestamp(timestamp)
185185

186+
@property
187+
def scheduled_at(self) -> Optional[datetime.datetime]:
188+
"""
189+
The timestamp (datetime) of when the task was intended to run — either
190+
the `when` value passed to `delay()`, or the time `delay()` was called
191+
if no `when` was given. Returns None if the task has never been queued.
192+
"""
193+
timestamp = self._data.get("scheduled_at")
194+
if timestamp is None:
195+
return None
196+
return datetime.datetime.utcfromtimestamp(timestamp)
197+
186198
@property
187199
def state(self) -> str:
188200
return self._state
@@ -373,6 +385,8 @@ def delay(
373385
else:
374386
state = SCHEDULED
375387

388+
self._data["scheduled_at"] = ts
389+
376390
# When using ALWAYS_EAGER, make sure we have serialized the task to
377391
# ensure there are no serialization errors.
378392
serialized_task = json.dumps(self._data)

tests/test_task.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import datetime
2+
13
import pytest
4+
from freezefrog import FreezeTime
25

36
from tasktiger import Task, TaskNotFound
47

@@ -49,3 +52,38 @@ def some_task():
4952

5053
task = tiger.delay(some_task, max_stored_executions=11)
5154
assert task.max_stored_executions == 11
55+
56+
57+
class TestScheduledAt:
58+
FROZEN_NOW = datetime.datetime(2024, 1, 1, 12, 0, 0)
59+
60+
def test_immediate_task_scheduled_at_equals_queue_time(self, tiger):
61+
with FreezeTime(self.FROZEN_NOW):
62+
task = tiger.delay(simple_task)
63+
assert task.scheduled_at == self.FROZEN_NOW
64+
65+
def test_future_task_scheduled_at_equals_when(self, tiger):
66+
future = datetime.timedelta(minutes=5)
67+
with FreezeTime(self.FROZEN_NOW):
68+
task = tiger.delay(simple_task, when=future)
69+
assert task.scheduled_at == self.FROZEN_NOW + future
70+
71+
def test_scheduled_at_survives_scheduled_to_queued_transition(self, tiger):
72+
future = datetime.timedelta(minutes=5)
73+
with FreezeTime(self.FROZEN_NOW):
74+
task = tiger.delay(simple_task, when=future)
75+
expected = self.FROZEN_NOW + future
76+
77+
task._move(from_state="scheduled", to_state="queued")
78+
reloaded = Task.from_id(tiger, task.queue, "queued", task.id)
79+
assert reloaded.scheduled_at == expected
80+
81+
def test_scheduled_at_persists_after_reload(self, tiger):
82+
with FreezeTime(self.FROZEN_NOW):
83+
task = tiger.delay(simple_task)
84+
reloaded = Task.from_id(tiger, task.queue, "queued", task.id)
85+
assert reloaded.scheduled_at == self.FROZEN_NOW
86+
87+
def test_scheduled_at_none_for_unqueued_task(self, tiger):
88+
task = Task(tiger, simple_task)
89+
assert task.scheduled_at is None

0 commit comments

Comments
 (0)