diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..2888a81 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "chat.tools.terminal.autoApprove": { + "cp": true + } +} \ No newline at end of file diff --git a/backend/core/database.py b/backend/core/database.py index 2ad789b..e0cc97d 100644 --- a/backend/core/database.py +++ b/backend/core/database.py @@ -51,6 +51,19 @@ async def get_session() -> AsyncIterator[AsyncSession]: raise +def open_session() -> AsyncSession: + """Return a standalone async session (for health checks, scripts, etc.). + + The caller uses ``async with`` to enter/exit:: + + async with open_session() as session: + await session.execute(...) + + The session is automatically closed on exit of the ``async with`` block. + """ + return _session_factory() + + # ── Valkey (Redis-compatible) ───────────────────────────────────────────── _valkey: Redis | None = None diff --git a/backend/routes/health.py b/backend/routes/health.py index 13c0163..40e565f 100644 --- a/backend/routes/health.py +++ b/backend/routes/health.py @@ -1,10 +1,36 @@ -"""Health-check endpoint.""" +"""Health-check endpoint — reports status of the API, database, and cache.""" + +from __future__ import annotations from fastapi import APIRouter +from sqlalchemy import text + +from backend.core.database import get_valkey, open_session router = APIRouter(tags=["health"]) @router.get("/api/health") async def health_check() -> dict[str, str]: - return {"status": "ok"} + """Return API, database, and Valkey health status.""" + result: dict[str, str] = {"status": "ok"} + + # ── PostgreSQL ───────────────────────────────────────────────────────── + try: + async with open_session() as session: + await session.execute(text("SELECT 1")) + result["database"] = "ok" + except Exception as exc: + result["database"] = f"error: {exc}" + result["status"] = "degraded" + + # ── Valkey / Redis ──────────────────────────────────────────────────── + try: + valkey = await get_valkey() + await valkey.ping() + result["cache"] = "ok" + except Exception as exc: + result["cache"] = f"error: {exc}" + result["status"] = "degraded" + + return result diff --git a/docker-compose.yml b/docker-compose.yml index 46175dc..12c945d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,10 +21,12 @@ services: ports: - "8000:8000" environment: + # NOTE: URLs are hardcoded to container service names so that the + # host .env file (with localhost URLs) does NOT override them. - LLM_BASE_URL=${LLM_BASE_URL:-http://host.docker.internal:11434/v1} - LLM_MODEL=${LLM_MODEL:-llama} - - DATABASE_URL=${DATABASE_URL:-postgresql+asyncpg://agent_alpha:agent_alpha@postgres:5432/agent_alpha} - - VALKEY_URL=${VALKEY_URL:-redis://valkey:6379/0} + - DATABASE_URL=postgresql+asyncpg://agent_alpha:agent_alpha@postgres:5432/agent_alpha + - VALKEY_URL=redis://valkey:6379/0 restart: unless-stopped depends_on: postgres: @@ -34,8 +36,10 @@ services: # Uncomment to use a local .env file instead of env vars: # env_file: # - .env + # Podman: use host.containers.internal; Docker Desktop: host.docker.internal extra_hosts: - "host.docker.internal:host-gateway" + - "host.containers.internal:host-gateway" # ── React Frontend (nginx) ────────────────────────────────────── frontend: diff --git a/frontend/nginx.conf b/frontend/nginx.conf index 6360c67..b12feb2 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -5,15 +5,10 @@ server { root /usr/share/nginx/html; index index.html; - # Podman/Docker DNS — forces runtime resolution so nginx picks up - # container IP changes after restarts. - resolver 10.89.6.1 valid=10s; - # ── API proxy ───────────────────────────────────────────────── - # Use a variable so nginx resolves DNS at runtime, not at startup. - set $backend_upstream http://backend:8000; + # Resolved at container startup (depends_on ensures backend is up). location /api/ { - proxy_pass $backend_upstream; + proxy_pass http://backend:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;