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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scheduler's CronSpec does not work with datetime.timezone offset

1 participant