mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-07-31 18:36:00 +00:00
fix(scheduler): normalize once-schedule next_run_at to UTC (#4607)
The once branch of next_run_at returned the run time with the task's local timezone offset attached, while the cron branch normalizes to UTC. The value is persisted into scheduled_tasks.next_run_at, and SQLAlchemy's SQLite dialect discards tzinfo on bind, so a once task declared in a non-UTC timezone fires shifted by the whole offset (e.g. 8 hours late for Asia/Shanghai, hours early for negative offsets - also bypassing the min_once_delay_seconds guard). Postgres timestamptz normalizes on write, which is why only SQLite deployments are affected. Align the once branch with the cron branch by converting to UTC before returning.
This commit is contained in:
parent
80848837b7
commit
486b51eb51
@ -41,6 +41,10 @@ def next_run_at(
|
||||
# A naive run_at means "wall-clock time in the task's declared
|
||||
# timezone", matching how cron schedules interpret it.
|
||||
run_at = run_at.replace(tzinfo=ZoneInfo(timezone_name))
|
||||
# Normalize to UTC like the cron branch: next_run_at is persisted to
|
||||
# timezone-discarding columns (SQLite), where a non-UTC offset shifts
|
||||
# the effective fire time by the whole offset.
|
||||
run_at = run_at.astimezone(UTC)
|
||||
return run_at if run_at > now else None
|
||||
|
||||
if schedule_type == "cron":
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from datetime import UTC, datetime
|
||||
from datetime import UTC, datetime, timedelta
|
||||
|
||||
import pytest
|
||||
|
||||
@ -38,6 +38,30 @@ def test_next_run_at_for_once_returns_none_after_fire_time():
|
||||
assert result is None
|
||||
|
||||
|
||||
def test_next_run_at_for_once_normalizes_naive_run_at_to_utc():
|
||||
now = datetime(2026, 7, 31, 0, 0, tzinfo=UTC)
|
||||
result = next_run_at(
|
||||
"once",
|
||||
{"run_at": "2026-08-01T09:00:00"},
|
||||
"Asia/Shanghai",
|
||||
now=now,
|
||||
)
|
||||
assert result == datetime(2026, 8, 1, 1, 0, tzinfo=UTC)
|
||||
assert result.utcoffset() == timedelta(0)
|
||||
|
||||
|
||||
def test_next_run_at_for_once_normalizes_aware_run_at_to_utc():
|
||||
now = datetime(2026, 7, 31, 0, 0, tzinfo=UTC)
|
||||
result = next_run_at(
|
||||
"once",
|
||||
{"run_at": "2026-08-01T09:00:00+08:00"},
|
||||
"UTC",
|
||||
now=now,
|
||||
)
|
||||
assert result == datetime(2026, 8, 1, 1, 0, tzinfo=UTC)
|
||||
assert result.utcoffset() == timedelta(0)
|
||||
|
||||
|
||||
def test_next_run_at_for_cron_uses_timezone():
|
||||
now = datetime(2026, 7, 1, 0, 30, tzinfo=UTC)
|
||||
result = next_run_at(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user