Default to America/Phoenix and email-alert once when the session expires
All checks were successful
Deploy / deploy (push) Successful in 25s

Phoenix doesn't observe DST, so schedule times stay meaningful
year-round without needing a seasonal adjustment.

notify.py reuses lunch-notifier's existing Gmail-SMTP-with-app-password
pattern rather than adding a new notification channel. The alert fires
exactly once per expiry (not on every failed scheduled run while it's
down) via a dedupe flag in notify_state.json, reset the moment a fresh
session is successfully imported.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6TgffxTvYhqxykAbVQg2v
This commit is contained in:
Barely Removable 2026-08-31 20:20:06 -07:00
parent 48d8bac332
commit 3b08af7938
7 changed files with 111 additions and 10 deletions

View file

@ -36,6 +36,7 @@ from datetime import datetime, timezone
from playwright.sync_api import sync_playwright
import notify
import storage
logger = logging.getLogger("massprice.automation")
@ -79,9 +80,33 @@ def _is_logged_out(page):
return "/Rule" not in page.url
def _notify_session_expired_once():
"""Send the email alert only on the first failure after the session
goes bad, not on every scheduled run that fails while it's down —
the flag resets when a fresh session is imported successfully."""
state = storage.load("notify_state.json", {})
if state.get("session_expired_notified"):
return
sent = notify.send_alert(
"MassPrice Scheduler: login session expired",
"The saved MassPrice session has expired or is missing. "
"Scheduled rule runs will keep failing until you log back in "
"via the Session page in the MassPrice Scheduler webui and "
"import a fresh cookie export.",
)
# Only mark as notified if the email actually sent — an unset/broken
# mail config shouldn't silently swallow the next attempt forever.
if sent:
storage.save(
"notify_state.json",
{"session_expired_notified": True, "notified_at": datetime.now(timezone.utc).isoformat()},
)
def _ensure_authenticated(page):
page.goto(f"{BASE_URL}/Rule/List")
if _is_logged_out(page):
_notify_session_expired_once()
raise AutomationError(
"MassPrice session expired or missing — log in via the "
"Session page and paste in a fresh cookie export."
@ -264,5 +289,6 @@ def import_cookies(raw_text):
"itself, after finishing login, not from the login page."
)
_save_state(context)
storage.save("notify_state.json", {"session_expired_notified": False})
finally:
browser.close()