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:
@@ -32,6 +32,9 @@ client = TestClient(app)
|
||||
@pytest.fixture(autouse=True)
|
||||
async def _reset():
|
||||
database.init_sqlite()
|
||||
# Simulate Oracle up for health tests (no real pool in unit env).
|
||||
_orig_pool = database.pool
|
||||
database.pool = object()
|
||||
db = await sqlite_service.get_sqlite()
|
||||
try:
|
||||
await db.execute("DELETE FROM sync_phase_failures")
|
||||
@@ -40,6 +43,7 @@ async def _reset():
|
||||
finally:
|
||||
await db.close()
|
||||
yield
|
||||
database.pool = _orig_pool
|
||||
|
||||
|
||||
async def _make_run(run_id: str, status: str = "completed", offset: int = 0,
|
||||
@@ -108,3 +112,12 @@ async def test_health_one_phase_failure_still_warning_not_healthy():
|
||||
# 1 recent phase failure → is_healthy stays True (<=1 tolerance); healthy
|
||||
assert data["is_healthy"] is True
|
||||
assert data["recent_phase_failures"]["invoice_check"] == 1
|
||||
|
||||
|
||||
async def test_health_oracle_down_not_healthy():
|
||||
await _make_run("ok-oracle", status="completed")
|
||||
database.pool = None # simulate Oracle pool not initialized
|
||||
r = client.get("/api/sync/health")
|
||||
data = r.json()
|
||||
assert data["oracle_ready"] is False
|
||||
assert data["is_healthy"] is False
|
||||
|
||||
Reference in New Issue
Block a user