Explorar el Código

Replace caldav_connection/calendar health keys with store_connected

Each backend now implements health_check(); CalDAV checks connection +
calendar exists, SQLite opens the DB. Status reports store_connected
regardless of which backend is active.
ZiB hace 4 meses
padre
commit
e38159cb5a

+ 12 - 26
room_cal/_health.py

@@ -5,7 +5,6 @@ import random
 from dataclasses import dataclass
 from datetime import datetime, timezone
 
-from room_cal.store import Calendar
 from room_cal.service_api import ServiceAPI
 from room_cal.service_api.types import ServiceAuthError
 from room_cal._utils import services
@@ -38,26 +37,14 @@ def get_cached() -> tuple[dict | None, bool]:
   return _cached, age > _CACHE_TTL
 
 
-async def caldav_checks() -> tuple[HealthResult, HealthResult]:
-  """Open one CalDAV connection and run both the connection and calendar-exists checks."""
-  from room_cal._utils import get_config
-  cfg = get_config()
-  if cfg.store.active != 'caldav':
-    return HealthResult(ok=True), HealthResult(ok=True)
-  cal_cfg = cfg.store.caldav
-  cal = Calendar(cal_cfg.calendar_name, url=cal_cfg.url, username=cal_cfg.username, password=cal_cfg.password)
+async def store_check() -> HealthResult:
+  """Ask the active store backend to report its own health."""
+  from room_cal.store import get_backend
   try:
-    async with await cal._client() as client:
-      conn = HealthResult(ok=True)
-      try:
-        await cal._get_calendar(client)
-        cal_result = HealthResult(ok=True)
-      except Exception as e:
-        cal_result = HealthResult(ok=False, reason=str(e))
+    ok, reason = await get_backend().health_check()
+    return HealthResult(ok=ok, reason=reason)
   except Exception as e:
-    conn = HealthResult(ok=False, reason=str(e))
-    cal_result = HealthResult(ok=False, reason='connection failed')
-  return conn, cal_result
+    return HealthResult(ok=False, reason=str(e))
 
 
 async def _probe_service(key: str, api: ServiceAPI) -> HealthResult:
@@ -98,26 +85,25 @@ async def probe_once() -> None:
   periodic_disabled = bool(os.getenv('DISABLE_PERIODIC'))
   try:
     api = ServiceAPI()
-    conn, cal_result = await caldav_checks()
+    store_result = await store_check()
     creds = {} if periodic_disabled else await credentials_checks(api)
-    caldav_ok = conn.ok and cal_result.ok
+    store_ok = store_result.ok
     creds_ok = all(v.ok for v in creds.values())
-    if caldav_ok and creds_ok:
+    if store_ok and creds_ok:
       overall = 'ok'
-    elif caldav_ok:
+    elif store_ok:
       overall = 'degraded'
     else:
       overall = 'error'
     _cached = {
       'status': overall,
       'checks': {
-        'caldav_connection': conn.to_dict(),
-        'calendar': cal_result.to_dict(),
+        'store_connected': store_result.to_dict(),
         'credentials': {k: v.to_dict() for k, v in creds.items()},
       },
       'checked_at': datetime.now(timezone.utc).isoformat(),
     }
-    if caldav_ok and creds_ok:
+    if store_ok and creds_ok:
       from room_cal._periodic import run_due, _register_all_periodics
       _register_all_periodics()
       await run_due(api)

+ 3 - 6
room_cal/api/_routes/health.py

@@ -12,14 +12,11 @@ async def healthcheck():
   if result is None:
     return JSONResponse({'status': 'starting'}, status_code=503)
   checks = result.get('checks', {})
-  caldav_ok = (
-    checks.get('caldav_connection', {}).get('ok', False)
-    and checks.get('calendar', {}).get('ok', False)
-  )
-  if caldav_ok:
+  store_ok = checks.get('store_connected', {}).get('ok', False)
+  if store_ok:
     return JSONResponse({'status': 'ok'})
   return JSONResponse(
-    {'status': 'error', 'checks': {k: checks[k] for k in ('caldav_connection', 'calendar') if k in checks}},
+    {'status': 'error', 'checks': {'store_connected': checks['store_connected']} if 'store_connected' in checks else {}},
     status_code=503,
   )
 

+ 1 - 0
room_cal/store/_backend.py

@@ -16,6 +16,7 @@ class EventRecord:
 
 
 class EventBackend(Protocol):
+  async def health_check(self) -> tuple[bool, str | None]: ...
   async def fetch_range(self, start: datetime, end: datetime) -> list[EventRecord]: ...
   async def create(self, record: EventRecord) -> EventRecord: ...
   async def update(self, uid: str, *, title: str | None = None,

+ 8 - 0
room_cal/store/_caldav.py

@@ -238,6 +238,14 @@ class CalDAVBackend:
     cal_cfg = store_cfg.caldav
     return cls(Calendar(cal_cfg.calendar_name, url=cal_cfg.url, username=cal_cfg.username, password=cal_cfg.password))
 
+  async def health_check(self) -> tuple[bool, str | None]:
+    try:
+      async with await self._cal._client() as client:
+        await self._cal._get_calendar(client)
+    except Exception as e:
+      return False, str(e)
+    return True, None
+
   def clear_cache(self):
     self._cal._event_cache.clear()
     self._cal._cached_url = None

+ 8 - 0
room_cal/store/_sqlite.py

@@ -65,6 +65,14 @@ class SQLiteBackend:
         conn.execute(_CREATE_INDEX)
     return cls(db_path)
 
+  async def health_check(self) -> tuple[bool, str | None]:
+    try:
+      async with self._connect() as db:
+        await db.execute('SELECT 1')
+    except Exception as e:
+      return False, str(e)
+    return True, None
+
   @asynccontextmanager
   async def _connect(self):
     import aiosqlite

+ 1 - 1
room_cal/vue/calendar.html

@@ -1536,7 +1536,7 @@ createApp({
         const v = await resp.json();
         healthChecks.value = v.checks;
         const c = v.checks || {};
-        const critical = (c.caldav_connection && !c.caldav_connection.ok) || (c.calendar && !c.calendar.ok);
+        const critical = c.store_connected && !c.store_connected.ok;
         const partial  = Object.values(c.credentials || {}).some(x => !x.ok);
         healthStatus.value = critical ? 'error' : partial ? 'warn' : 'ok';
       } catch {