mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-08-01 10:56:02 +00:00
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.
74 lines
1.9 KiB
Python
74 lines
1.9 KiB
Python
from datetime import UTC, datetime, timedelta
|
|
|
|
import pytest
|
|
|
|
from deerflow.scheduler.schedules import (
|
|
next_run_at,
|
|
normalize_cron_expression,
|
|
validate_timezone,
|
|
)
|
|
|
|
|
|
def test_validate_timezone_accepts_iana_name():
|
|
assert validate_timezone("Asia/Shanghai") == "Asia/Shanghai"
|
|
|
|
|
|
def test_validate_timezone_rejects_unknown_name():
|
|
with pytest.raises(ValueError):
|
|
validate_timezone("Mars/Base")
|
|
|
|
|
|
def test_normalize_cron_accepts_five_fields():
|
|
assert normalize_cron_expression("0 9 * * 1") == "0 9 * * 1"
|
|
|
|
|
|
def test_normalize_cron_rejects_seconds_field():
|
|
with pytest.raises(ValueError):
|
|
normalize_cron_expression("0 0 9 * * 1")
|
|
|
|
|
|
def test_next_run_at_for_once_returns_none_after_fire_time():
|
|
now = datetime(2026, 7, 2, 2, 0, tzinfo=UTC)
|
|
result = next_run_at(
|
|
"once",
|
|
{"run_at": "2026-07-02T01:00:00+00:00"},
|
|
"UTC",
|
|
now=now,
|
|
)
|
|
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(
|
|
"cron",
|
|
{"cron": "0 9 * * *"},
|
|
"Asia/Shanghai",
|
|
now=now,
|
|
)
|
|
assert result == datetime(2026, 7, 1, 1, 0, tzinfo=UTC)
|