Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/sentry/monitors/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import uuid
import zoneinfo
from collections.abc import Sequence
from datetime import datetime
from datetime import UTC, datetime
from functools import cache
from typing import TYPE_CHECKING, ClassVar, Self, override
from uuid import uuid4
Expand Down Expand Up @@ -353,7 +353,8 @@ def get_next_expected_checkin_latest(self, last_checkin: datetime) -> datetime:
"""
from sentry.monitors.utils import get_checkin_margin

next_checkin = self.get_next_expected_checkin(last_checkin)
# Add the margin in UTC: local wall-clock arithmetic drops the DST fold
next_checkin = self.get_next_expected_checkin(last_checkin).astimezone(UTC)
return next_checkin + get_checkin_margin(self.config.get("checkin_margin"))

def update_config(self, config_payload, validated_config):
Expand Down
22 changes: 22 additions & 0 deletions tests/sentry/monitors/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,28 @@ def test_next_run_latest_crontab_with_margin(self) -> None:
2019, 1, 1, 1, 16, tzinfo=timezone.utc
)

def test_next_run_latest_crontab_during_dst_fold(self) -> None:
# Europe/Berlin repeats 02:00-02:59 local time on 2024-10-27 from 01:00 UTC
ts = datetime(2024, 10, 27, 1, 0, 3, tzinfo=timezone.utc)
monitor = Monitor(
config={
"schedule_type": ScheduleType.CRONTAB,
"schedule": "* * * * *",
"timezone": "Europe/Berlin",
"checkin_margin": 5,
"max_runtime": None,
}
)
monitor_environment = MonitorEnvironment(monitor=monitor, last_checkin=ts)

# PEP 495: inter-zone == is always False for a time with fold=1
assert monitor_environment.monitor.get_next_expected_checkin(ts).astimezone(
timezone.utc
) == datetime(2024, 10, 27, 1, 1, tzinfo=timezone.utc)
assert monitor_environment.monitor.get_next_expected_checkin_latest(ts) == datetime(
2024, 10, 27, 1, 6, tzinfo=timezone.utc
)

def test_next_run_crontab_with_timezone(self) -> None:
ts = datetime(2019, 1, 1, 1, 10, 20, tzinfo=timezone.utc)
monitor = Monitor(
Expand Down
Loading