Skip to content

fix: round-trip timedelta cron offset (#605)#625

Open
sfrangulov wants to merge 1 commit into
taskiq-python:masterfrom
sfrangulov:fix/cron-offset-timedelta-roundtrip
Open

fix: round-trip timedelta cron offset (#605)#625
sfrangulov wants to merge 1 commit into
taskiq-python:masterfrom
sfrangulov:fix/cron-offset-timedelta-roundtrip

Conversation

@sfrangulov

Copy link
Copy Markdown

What

A timedelta cron offset breaks after a serialize→deserialize round-trip. pydantic serializes a timedelta to an ISO-8601 duration string (e.g. "PT4H"); because the offset fields are typed str | timedelta, on reload the value stays a str, so is_cron_task_now takes the timezone-name branch and calls ZoneInfo("PT4H") → the schedule breaks.

Reproduction (from #605):

>>> CronSpec.model_validate(CronSpec(offset=datetime.now().astimezone().tzinfo.utcoffset(None)).model_dump(mode="json"))
CronSpec(..., offset='PT2H')   # expected: timedelta(seconds=7200)

Fix

Add a shared parse_cron_offset validator (scheduler/scheduled_task/validators.py) that restores a timedelta from its serialized ISO-8601 duration form, while leaving genuine timezone names (e.g. "US/Eastern") and all other values untouched — a timezone name is not a valid duration, so it is safely passed through.

Applied as a before-validator on:

  • CronSpec.offset
  • ScheduledTask.cron_offset (pydantic v1 and v2 models)

Tests

tests/scheduler/test_cron_offset_roundtrip.py — round-trip for CronSpec and ScheduledTask with timedelta offsets, plus regression guards that timezone-name offsets are preserved.

Verification (local)

  • New + existing scheduler/cron tests pass (tests/scheduler/, tests/cli/scheduler/).
  • ruff, black, mypy clean on changed files.
  • Verified on pydantic v2 (environment). The pydantic v1 branch mirrors the existing dual-version validator idiom already used in taskiq/result/result.py and shares the same helper.

Closes #605

pydantic serializes a timedelta offset to an ISO-8601 duration string
(e.g. "PT4H"). Because the offset fields are typed as str | timedelta,
re-validating kept the value as a str, so the scheduler later passed it
to ZoneInfo("PT4H") and the schedule broke.

Add a shared parse_cron_offset validator that restores a timedelta from
its serialized duration form while leaving genuine timezone names (e.g.
"US/Eastern") and other values untouched. Apply it as a before-validator
on CronSpec.offset and ScheduledTask.cron_offset (pydantic v1 and v2).

Closes taskiq-python#605
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant