From 43c8d6c29caf77fb8ace64c986ef4bb45770fa66 Mon Sep 17 00:00:00 2001 From: Trevin Chow Date: Thu, 9 Apr 2026 21:44:33 -0700 Subject: [PATCH] fix(bluesky): add token expiry handling to session cache The module-level _cached_token was set once and never refreshed. AT Protocol tokens expire after ~2 hours, causing silent 401 errors in long-running watchlist cron sessions. Adds a 90-minute expiry check using time.monotonic() and logs re-authentication. Fixes #92 --- scripts/lib/bluesky.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/scripts/lib/bluesky.py b/scripts/lib/bluesky.py index 07ef4e8..7c3436a 100644 --- a/scripts/lib/bluesky.py +++ b/scripts/lib/bluesky.py @@ -7,6 +7,7 @@ Requires BSKY_HANDLE and BSKY_APP_PASSWORD env vars. import math import re import sys +import time from datetime import datetime, timezone from typing import Any, Dict, List, Optional @@ -23,7 +24,9 @@ DEPTH_CONFIG = { # Module-level token cache (valid for the lifetime of a single research run) _cached_token: Optional[str] = None +_token_created_at: float = 0.0 _session_error: Optional[str] = None +_TOKEN_MAX_AGE_SECONDS = 5400 # 90 minutes (conservative, tokens last ~2 hours) def _log(msg: str): @@ -40,9 +43,13 @@ def _create_session(handle: str, app_password: str) -> Optional[str]: Returns: Access JWT string, or None on failure. Sets _session_error on failure. """ - global _cached_token, _session_error - if _cached_token: + global _cached_token, _token_created_at, _session_error + if _cached_token and (time.monotonic() - _token_created_at < _TOKEN_MAX_AGE_SECONDS): return _cached_token + if _cached_token: + _log("Session token expired, re-authenticating") + _cached_token = None + _token_created_at = 0.0 try: response = http.request( @@ -54,6 +61,7 @@ def _create_session(handle: str, app_password: str) -> Optional[str]: token = response.get("accessJwt") if token: _cached_token = token + _token_created_at = time.monotonic() _session_error = None _log("Session created successfully") return token @@ -76,8 +84,9 @@ def _create_session(handle: str, app_password: str) -> Optional[str]: def _reset_session_cache() -> None: - global _cached_token, _session_error + global _cached_token, _token_created_at, _session_error _cached_token = None + _token_created_at = 0.0 _session_error = None