@@ -695,35 +695,34 @@ async def get_upcoming_events(
695695 self ,
696696 now_ns : int ,
697697 default_lookahead_ns : int ,
698+ grace_ns : int = 0 ,
698699 db : Optional [AsyncSession ] = None ,
699700 ) -> list [tuple [CalendarEventModel , Optional [str ]]]:
700701 """Events starting between now and now + lookahead, for alert processing.
701702
702703 Per-event lookahead is read from meta.alert_minutes (falls back to
703704 default_lookahead_ns). Returns (event, user_timezone) pairs.
705+
706+ *grace_ns* widens the SQL lower bound so that events whose start_at
707+ is up to *grace_ns* nanoseconds in the past are still fetched. This
708+ ensures "At time of event" alerts (alert_minutes=0) are not missed
709+ when the scheduler polls a few seconds after the event's exact start
710+ time.
704711 """
705712 from open_webui .models .users import User as UserRow
706- from open_webui .utils .automations import SCHEDULER_POLL_INTERVAL
707713
708714 # Use the maximum possible lookahead (60 min) to cast a wide net;
709715 # per-event filtering happens in Python after fetching.
710716 max_lookahead_ns = max (default_lookahead_ns , 60 * 60 * 1_000_000_000 )
711717 upper = now_ns + max_lookahead_ns
712718
713- # Grace window: allow events whose start_at is up to one poll cycle
714- # in the past. This ensures "At time of event" alerts (alert_minutes=0)
715- # are not missed when the scheduler polls a few seconds after the
716- # event's exact start time.
717- grace_ns = (SCHEDULER_POLL_INTERVAL + 5 ) * 1_000_000_000
718- lower = now_ns - grace_ns
719-
720719 async with get_async_db_context (db ) as db :
721720 result = await db .execute (
722721 select (CalendarEvent , UserRow .timezone )
723722 .outerjoin (UserRow , UserRow .id == CalendarEvent .user_id )
724723 .filter (
725724 CalendarEvent .is_cancelled == False ,
726- CalendarEvent .start_at >= lower ,
725+ CalendarEvent .start_at >= now_ns - grace_ns ,
727726 CalendarEvent .start_at <= upper ,
728727 )
729728 )
@@ -741,9 +740,7 @@ async def get_upcoming_events(
741740 if alert_minutes < 0 :
742741 # alert_minutes < 0 means "no alert"
743742 continue
744- # For "at time of event" (0 minutes), use the grace window
745- # so events that just started are still captured.
746- event_lookahead_ns = max (alert_minutes * 60 * 1_000_000_000 , grace_ns )
743+ event_lookahead_ns = alert_minutes * 60 * 1_000_000_000
747744 else :
748745 event_lookahead_ns = default_lookahead_ns
749746
0 commit comments