diff --git a/Dockerfile b/Dockerfile index f349935..bed1e96 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,5 +20,8 @@ COPY frontend/ ./frontend/ # Expose port EXPOSE 8000 +HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ + CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/healthz', timeout=3).read()" || exit 1 + # Run -CMD ["uvicorn", "backend.app.main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file +CMD ["uvicorn", "backend.app.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/README.md b/README.md index d38e8e5..d2b9e6e 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ The app can still run without external AI providers when `LLM_ENABLED=false`. | API root | http://localhost:8000/ | | Interactive docs | http://localhost:8000/docs | | Health check | http://localhost:8000/health | +| Container health check | http://localhost:8000/healthz | | Signup | http://localhost:8000/auth/signup | | Login | http://localhost:8000/auth/login | | Current user | http://localhost:8000/auth/me | diff --git a/backend/Dockerfile b/backend/Dockerfile index f349935..bed1e96 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -20,5 +20,8 @@ COPY frontend/ ./frontend/ # Expose port EXPOSE 8000 +HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ + CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/healthz', timeout=3).read()" || exit 1 + # Run -CMD ["uvicorn", "backend.app.main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file +CMD ["uvicorn", "backend.app.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/backend/app/main.py b/backend/app/main.py index e868905..ee22421 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -206,6 +206,11 @@ async def health_check(): } +@app.get("/healthz", tags=["System"]) +async def healthz(): + return {"status": "ok"} + + @app.get("/ping", tags=["System"]) async def ping(): return {"message": "pong"} diff --git a/backend/tests/test_endpoints.py b/backend/tests/test_endpoints.py index c4d776b..b39be9b 100644 --- a/backend/tests/test_endpoints.py +++ b/backend/tests/test_endpoints.py @@ -165,6 +165,12 @@ def test_health(): assert r.json()["status"] == "ok" +def test_healthz(): + r = client.get("/healthz") + assert r.status_code == 200 + assert r.json() == {"status": "ok"} + + def test_rate_limit_headers_on_success_response(): r = client.get("/") assert r.status_code == 200 diff --git a/docker-compose.yml b/docker-compose.yml index 244a006..323dd0f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,6 +11,12 @@ services: volumes: - ./backend:/app/backend command: uvicorn backend.app.main:app --host 0.0.0.0 --port 8000 --reload + healthcheck: + test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/healthz', timeout=3).read()"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s depends_on: - db @@ -38,4 +44,4 @@ services: - postgres_data:/var/lib/postgresql/data volumes: - postgres_data: \ No newline at end of file + postgres_data: