fix(scheduler): honor app timezone for cron triggers and log scheduled events
CronTrigger.from_crontab was constructed without a timezone, so a cron like '0 9 * * *' fired at 09:00 host-local instead of 09:00 in the admin-configured timezone. Now all tracker/action cron triggers are built with the app tz, and the setting endpoint rebuilds existing cron jobs when the tz changes (since CronTrigger freezes its tz at construction time). The scheduler provider also renders current_date/time/datetime/weekday in the configured tz and exposes a new 'timezone' template variable. EventLog entries for scheduled_message now include schedule_type, cron_expression/interval_seconds, timezone, and fire_count, and the dashboard shows the event type with a label/icon/color.
This commit is contained in:
@@ -246,6 +246,7 @@ async def check_tracker(tracker_id: int) -> dict[str, Any]:
|
||||
name=provider_name,
|
||||
tracker_name=tracker_name,
|
||||
custom_variables=custom_vars,
|
||||
timezone_name=app_tz,
|
||||
)
|
||||
events, new_state = await sched.poll(collection_ids, state_dict)
|
||||
elif provider_type == "nut":
|
||||
@@ -317,6 +318,26 @@ async def check_tracker(tracker_id: int) -> dict[str, Any]:
|
||||
|
||||
for event in events:
|
||||
assets_count = event.added_count or event.removed_count or 0
|
||||
details: dict[str, Any] = {
|
||||
"added_count": event.added_count,
|
||||
"removed_count": event.removed_count,
|
||||
"provider_type": event.provider_type.value,
|
||||
}
|
||||
# Scheduler/periodic events carry the schedule context in ``extra``
|
||||
# (cron expression, interval, timezone, fire count). Surface that
|
||||
# in the event log so the dashboard and audit queries can show
|
||||
# *why* the event fired, not just that it did.
|
||||
if event.event_type.value == "scheduled_message":
|
||||
sched_type = tracker_filters.get("schedule_type", "interval")
|
||||
details["schedule_type"] = sched_type
|
||||
if sched_type == "cron":
|
||||
details["cron_expression"] = tracker_filters.get("cron_expression", "")
|
||||
else:
|
||||
details["interval_seconds"] = tracker.scan_interval
|
||||
details["timezone"] = app_tz
|
||||
fire_count = event.extra.get("fire_count") if event.extra else None
|
||||
if fire_count is not None:
|
||||
details["fire_count"] = fire_count
|
||||
log = EventLog(
|
||||
user_id=tracker.user_id,
|
||||
tracker_id=tracker_id,
|
||||
@@ -327,11 +348,7 @@ async def check_tracker(tracker_id: int) -> dict[str, Any]:
|
||||
collection_id=event.collection_id,
|
||||
collection_name=event.collection_name,
|
||||
assets_count=assets_count,
|
||||
details={
|
||||
"added_count": event.added_count,
|
||||
"removed_count": event.removed_count,
|
||||
"provider_type": event.provider_type.value,
|
||||
},
|
||||
details=details,
|
||||
)
|
||||
session.add(log)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user