AdithyaVardan commited on
Commit
e68bb19
·
1 Parent(s): f79d4f9

fix: in-memory session fallback when Redis is unreachable

Browse files

Upstash free tier can pause after inactivity. Rather than returning 503,
fall back to a module-level dict so login works on single-process deploys
like HuggingFace Spaces. Redis is still tried first.

Files changed (1) hide show
  1. src/auth/router.py +34 -22
src/auth/router.py CHANGED
@@ -81,39 +81,51 @@ async def _redis() -> aioredis.Redis:
81
  )
82
 
83
 
 
 
 
 
84
  async def _get_session(session_id: str) -> dict | None:
85
- r = await _redis()
86
  try:
87
- raw = await r.get(f"gs:session:{session_id}")
88
- return json.loads(raw) if raw else None
89
- except Exception as exc:
90
- logger.warning("session_read_failed", extra={"error": str(exc)})
91
- return None
92
- finally:
93
- await r.aclose()
 
 
 
 
 
94
 
95
 
96
  async def _set_session(session_id: str, payload: dict) -> bool:
97
- """Returns False if Redis is unavailable."""
98
- r = await _redis()
99
  try:
100
- await r.setex(f"gs:session:{session_id}", SESSION_TTL, json.dumps(payload))
101
- return True
 
 
 
 
102
  except Exception as exc:
103
- logger.error("session_write_failed", extra={"error": str(exc)})
104
- return False
105
- finally:
106
- await r.aclose()
107
 
108
 
109
  async def _del_session(session_id: str) -> None:
110
- r = await _redis()
111
  try:
112
- await r.delete(f"gs:session:{session_id}")
113
- except Exception as exc:
114
- logger.warning("session_delete_failed", extra={"error": str(exc)})
115
- finally:
116
- await r.aclose()
 
 
117
 
118
 
119
  # ---------------------------------------------------------------------------
 
81
  )
82
 
83
 
84
+ # In-memory fallback when Redis is unreachable (single-process deploy)
85
+ _mem_sessions: dict[str, str] = {}
86
+
87
+
88
  async def _get_session(session_id: str) -> dict | None:
 
89
  try:
90
+ r = await _redis()
91
+ try:
92
+ raw = await r.get(f"gs:session:{session_id}")
93
+ if raw:
94
+ return json.loads(raw)
95
+ finally:
96
+ await r.aclose()
97
+ except Exception:
98
+ pass
99
+ # Fallback to in-memory
100
+ raw = _mem_sessions.get(session_id)
101
+ return json.loads(raw) if raw else None
102
 
103
 
104
  async def _set_session(session_id: str, payload: dict) -> bool:
105
+ serialised = json.dumps(payload)
 
106
  try:
107
+ r = await _redis()
108
+ try:
109
+ await r.setex(f"gs:session:{session_id}", SESSION_TTL, serialised)
110
+ return True
111
+ finally:
112
+ await r.aclose()
113
  except Exception as exc:
114
+ logger.warning("redis_unavailable — using in-memory session store", extra={"error": str(exc)})
115
+ _mem_sessions[session_id] = serialised
116
+ return True
 
117
 
118
 
119
  async def _del_session(session_id: str) -> None:
120
+ _mem_sessions.pop(session_id, None)
121
  try:
122
+ r = await _redis()
123
+ try:
124
+ await r.delete(f"gs:session:{session_id}")
125
+ finally:
126
+ await r.aclose()
127
+ except Exception:
128
+ pass
129
 
130
 
131
  # ---------------------------------------------------------------------------