feat(oracle): auto-recover Oracle pool + surface status, stop silent import failures
After a power loss the app started before Oracle was ready; init_oracle() failed
once, the pool stayed None forever (no retry), and every sync silently failed
("Oracle pool not initialized") while still hammering the GoMag API each minute,
and order-detail 500'd.
- database.ensure_oracle_pool(force): thread-safe (re)create of the pool, called
at the start of every sync cycle → self-heals within one cycle once Oracle is
back (incl. after an Oracle service restart). init_oracle_client made idempotent
so re-init can't fall back to thin mode.
- database.oracle_status() exposed; main.py startup is non-fatal via ensure pool.
- run_sync ensures the pool before the GoMag download; on failure it records a
clear run status instead of crashing and skips the wasted API calls.
- /api/sync/health reports oracle_ready/last_error; dashboard health pill shows
"Oracle indisponibil" (top priority). Recovery via the existing Start Sync button.
- order_detail degrades gracefully (200 without CODMAT + notice) instead of 500.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -338,6 +338,26 @@ async def run_sync(id_pol: int = None, id_sectie: int = None, run_id: str = None
|
||||
return {"run_id": run_id, "status": "halted_escalation", "error": halt_msg}
|
||||
|
||||
try:
|
||||
# Phase -1: Ensure Oracle pool (auto-recovery after a DB restart).
|
||||
# Done before the GoMag download so we don't waste API calls every
|
||||
# cycle while Oracle is down, and so users get a clear status.
|
||||
if not await asyncio.to_thread(database.ensure_oracle_pool):
|
||||
last_err = database.oracle_status().get("last_error") or "fara detalii"
|
||||
msg = ("Oracle indisponibil — pool neinitializat. Import oprit; "
|
||||
"se reincearca automat la urmatorul ciclu de sync. "
|
||||
f"Detalii: {last_err}")
|
||||
_log_line(run_id, f"EROARE: {msg}")
|
||||
await sqlite_service.create_sync_run(run_id, 0)
|
||||
await sqlite_service.update_sync_run(
|
||||
run_id, "failed", 0, 0, 0, 0, error_message=msg
|
||||
)
|
||||
if _current_sync:
|
||||
_current_sync["status"] = "failed"
|
||||
_current_sync["finished_at"] = _now().isoformat()
|
||||
_current_sync["error"] = msg
|
||||
_update_progress("failed", "Oracle indisponibil — import oprit")
|
||||
return {"run_id": run_id, "status": "failed", "error": msg}
|
||||
|
||||
# Phase 0: Download orders from GoMag API
|
||||
_update_progress("downloading", "Descărcare comenzi din GoMag API...")
|
||||
_log_line(run_id, "Descărcare comenzi din GoMag API...")
|
||||
|
||||
Reference in New Issue
Block a user