throttle polling outside business hours
Single DAG, single 30-min schedule instead of 5-min or two separate DAGs. run_sync() itself decides whether to do real work: always during business hours (default 07:00-17:00 WIB), otherwise only once per EDOXID_OFF_HOURS_INTERVAL_MINUTES (default 120) tracked via a last_full_sync timestamp in the sqlite state. Off-hours skips return immediately without touching DB/Calendar/Gmail at all.
This commit is contained in:
@@ -6,8 +6,10 @@ from datetime import datetime, timedelta
|
||||
import pytz
|
||||
|
||||
from scripts.edoxid_calendar_config import (
|
||||
get_business_hours,
|
||||
get_db_config,
|
||||
get_google_config,
|
||||
get_off_hours_interval_minutes,
|
||||
get_state_sqlite_path,
|
||||
get_sync_min_date,
|
||||
)
|
||||
@@ -27,15 +29,32 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
JAKARTA_TZ = pytz.timezone("Asia/Jakarta")
|
||||
|
||||
# Toleransi jendela waktu untuk cek reminder — harus >= interval polling DAG (5 menit)
|
||||
# supaya tidak ada window yang "kelewat" di antara 2 run.
|
||||
REMINDER_WINDOW = timedelta(minutes=10)
|
||||
|
||||
def _should_run_now(now: datetime, state: StateStore) -> bool:
|
||||
"""DAG tetap trigger tiap 30 menit sepanjang hari (1 DAG, 1 schedule —
|
||||
lebih sederhana dari 2 DAG terpisah), tapi kerja BENERAN (baca DB, panggil
|
||||
Calendar/Gmail API) cuma jalan penuh saat jam kerja, atau di luar jam kerja
|
||||
kalau sudah >= EDOXID_OFF_HOURS_INTERVAL_MINUTES sejak sync terakhir."""
|
||||
start, end = get_business_hours()
|
||||
if start <= now.hour < end:
|
||||
return True
|
||||
|
||||
last = state.get_last_full_sync()
|
||||
if last is None:
|
||||
return True
|
||||
if last.tzinfo is None:
|
||||
last = JAKARTA_TZ.localize(last)
|
||||
|
||||
return now - last >= timedelta(minutes=get_off_hours_interval_minutes())
|
||||
|
||||
|
||||
def _check_and_send_reminders(submissions: list[dict], state: StateStore, gmail: GmailService) -> int:
|
||||
"""Kirim email reminder H-1 (07:00) & 1 jam sebelum ke semua attendee —
|
||||
terpisah dari reminders.overrides Calendar (yang cuma berlaku untuk
|
||||
calendar TU sendiri, tidak ikut ke kalender pribadi tiap attendee)."""
|
||||
# Toleransi jendela harus >= jarak terbesar antar-run BENERAN (di luar jam
|
||||
# kerja), supaya H-1/1-jam tidak "kelewat" gara-gara run di antaranya di-skip.
|
||||
reminder_window = timedelta(minutes=get_off_hours_interval_minutes() + 5)
|
||||
now = datetime.now(JAKARTA_TZ)
|
||||
sent = 0
|
||||
|
||||
@@ -47,7 +66,7 @@ def _check_and_send_reminders(submissions: list[dict], state: StateStore, gmail:
|
||||
if not emails:
|
||||
continue
|
||||
|
||||
if h1_time <= now < h1_time + REMINDER_WINDOW and not state.is_notified(submission["id"], "h1"):
|
||||
if h1_time <= now < h1_time + reminder_window and not state.is_notified(submission["id"], "h1"):
|
||||
subject = f"[PENGINGAT SEBELUM H-1] {get_type_label(submission)} — {submission['student_name']}"
|
||||
gmail.send(emails, subject, build_description(submission))
|
||||
state.mark_notified(submission["id"], "h1")
|
||||
@@ -57,7 +76,7 @@ def _check_and_send_reminders(submissions: list[dict], state: StateStore, gmail:
|
||||
submission["id"], format_submission_summary(submission), ", ".join(emails),
|
||||
)
|
||||
|
||||
if one_hour_time <= now < one_hour_time + REMINDER_WINDOW and not state.is_notified(
|
||||
if one_hour_time <= now < one_hour_time + reminder_window and not state.is_notified(
|
||||
submission["id"], "1h"
|
||||
):
|
||||
subject = f"[PENGINGAT 1 JAM SEBELUM] {get_type_label(submission)} — {submission['student_name']}"
|
||||
@@ -73,8 +92,21 @@ def _check_and_send_reminders(submissions: list[dict], state: StateStore, gmail:
|
||||
|
||||
|
||||
def run_sync() -> dict:
|
||||
db = Database(get_db_config())
|
||||
state = StateStore(get_state_sqlite_path())
|
||||
now = datetime.now(JAKARTA_TZ)
|
||||
|
||||
if not _should_run_now(now, state):
|
||||
start, end = get_business_hours()
|
||||
logger.info(
|
||||
"Di luar jam kerja (%02d:00-%02d:00 WIB) dan belum %s menit sejak sync terakhir — skip run ini.",
|
||||
start, end, get_off_hours_interval_minutes(),
|
||||
)
|
||||
state.close()
|
||||
return {"skipped_off_hours": True}
|
||||
|
||||
state.set_last_full_sync(now)
|
||||
|
||||
db = Database(get_db_config())
|
||||
google_config = get_google_config()
|
||||
calendar = GoogleCalendarService(google_config)
|
||||
gmail = GmailService(google_config)
|
||||
|
||||
Reference in New Issue
Block a user