feat: graceful shutdown with store persistence and restart overlay
Some checks failed
Lint & Test / test (push) Failing after 29s
Some checks failed
Lint & Test / test (push) Failing after 29s
- Add /api/v1/system/shutdown endpoint that triggers clean uvicorn exit - Persist all 15 stores to disk during shutdown via _save_all_stores() - Add force parameter to BaseJsonStore._save() to bypass restore freeze - Restart script now requests graceful shutdown via API (15s timeout), falls back to force-kill only if server doesn't exit in time - Broadcast server_restarting event over WebSocket before shutdown - Frontend shows "Server restarting..." overlay instantly on WS event, replacing the old dynamically-created overlay from settings.ts - Add server_ref module to share uvicorn Server + TrayManager refs - Add i18n keys for restart overlay (en/ru/zh)
This commit is contained in:
@@ -92,6 +92,29 @@ processor_manager = ProcessorManager(
|
||||
)
|
||||
|
||||
|
||||
def _save_all_stores() -> None:
|
||||
"""Persist every store to disk.
|
||||
|
||||
Called during graceful shutdown to ensure in-memory data survives
|
||||
restarts even if no CRUD happened during the session.
|
||||
"""
|
||||
all_stores = [
|
||||
device_store, template_store, pp_template_store,
|
||||
picture_source_store, output_target_store, pattern_template_store,
|
||||
color_strip_store, audio_source_store, audio_template_store,
|
||||
value_source_store, automation_store, scene_preset_store,
|
||||
sync_clock_store, cspt_store, gradient_store,
|
||||
]
|
||||
saved = 0
|
||||
for store in all_stores:
|
||||
try:
|
||||
store._save(force=True)
|
||||
saved += 1
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to save {store._json_key} on shutdown: {e}")
|
||||
logger.info(f"Shutdown save: persisted {saved}/{len(all_stores)} stores to disk")
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
"""Application lifespan manager.
|
||||
@@ -230,6 +253,11 @@ async def lifespan(app: FastAPI):
|
||||
# Shutdown
|
||||
logger.info("Shutting down LED Grab")
|
||||
|
||||
# Persist all stores to disk before stopping anything.
|
||||
# This ensures in-memory data survives force-kills and restarts
|
||||
# where no CRUD happened during the session.
|
||||
_save_all_stores()
|
||||
|
||||
# Stop auto-backup engine
|
||||
try:
|
||||
await auto_backup_engine.stop()
|
||||
|
||||
Reference in New Issue
Block a user