Skip to content

Commit

Permalink
Merge pull request #22 from xyvora/state
Browse files Browse the repository at this point in the history
Initial setup of cache
  • Loading branch information
sanders41 authored Dec 23, 2024
2 parents cd93c2a + 2f0cab0 commit e2b5829
Show file tree
Hide file tree
Showing 13 changed files with 124 additions and 5 deletions.
15 changes: 15 additions & 0 deletions backend/app/api/deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import asyncpg
import jwt
import valkey.asyncio as valkey
from fastapi import Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
from jwt.exceptions import InvalidTokenError
Expand All @@ -15,6 +16,7 @@
HTTP_503_SERVICE_UNAVAILABLE,
)

from app.core.cache import cache
from app.core.config import settings
from app.core.db import db
from app.core.security import ALGORITHM
Expand All @@ -39,6 +41,19 @@ async def get_db_conn() -> AsyncGenerator[asyncpg.Connection, None]:
DbConn = Annotated[asyncpg.Connection, Depends(get_db_conn)]


async def get_cache_client() -> AsyncGenerator[valkey.Valkey, None]:
if cache.client is None:
logger.error("No cache client created")
raise HTTPException(
status_code=HTTP_503_SERVICE_UNAVAILABLE, detail="The cache is currently unavailable"
)

yield cache.client


CacheClient = Annotated[valkey.Valkey, Depends(get_cache_client)]


async def get_current_user(conn: DbConn, token: TokenDep) -> UserInDb:
try:
logger.debug("Decoding JWT token")
Expand Down
12 changes: 10 additions & 2 deletions backend/app/api/routes/health.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from loguru import logger

from app.api.deps import DbConn
from app.api.deps import CacheClient, DbConn
from app.core.config import settings
from app.core.utils import APIRouter
from app.services.db_services import ping
Expand All @@ -11,7 +11,7 @@


@router.get("/")
async def health(*, db_conn: DbConn) -> dict[str, str]:
async def health(*, cache_client: CacheClient, db_conn: DbConn) -> dict[str, str]:
"""Check the health of the server."""

logger.debug("Checking health")
Expand All @@ -25,4 +25,12 @@ async def health(*, db_conn: DbConn) -> dict[str, str]:
logger.error(f"Unable to ping the database: {e}")
health["db"] = "unhealthy"

logger.debug("Checking cache health")
try:
await cache_client.ping()
health["cache"] = "healthy"
except Exception as e:
logger.error(f"Unable to ping the cache server: {e}")
health["cache"] = "unhealthy"

return health
35 changes: 35 additions & 0 deletions backend/app/core/cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import valkey.asyncio as valkey

from app.core.config import settings


class Cache:
def __init__(self) -> None:
self._pool: valkey.ConnectionPool | None = None
self.client: valkey.Valkey | None = None

async def create_client(self) -> None:
self._pool = await self._create_pool()
self.client = valkey.Valkey.from_pool(self._pool)

async def close_client(self) -> None:
if self.client:
await self.client.aclose()

if self._pool:
await self._pool.aclose()

async def _create_pool(self) -> valkey.ConnectionPool:
return valkey.ConnectionPool(
host=settings.VALKEY_HOST,
port=settings.VALKEY_PORT,
password=settings.VALKEY_PASSWORD.get_secret_value(),
db=0,
)

async def _close_pool(self) -> None:
if self._pool:
await self._pool.aclose()


cache = Cache()
4 changes: 4 additions & 0 deletions backend/app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ class Settings(BaseSettings):
POSTGRES_USER: str
POSTGRES_PASSWORD: SecretStr
POSTGRES_DB: str = "scan"
VALKEY_HOST: str
VALKEY_PASSWORD: SecretStr
VALKEY_PORT: int = 6379
OPENAI_API_KEY: SecretStr
DLPFC_MODEL: SecretStr = SecretStr("gpt-3.5-turbo")
VMPFC_MODEL: SecretStr = SecretStr("gpt-3.5-turbo")
Expand Down Expand Up @@ -89,6 +92,7 @@ def _enforce_non_default_secrets(self) -> Self:
)
self._check_default_secret("POSTGRES_USER", self.POSTGRES_USER)
self._check_default_secret("POSTGRES_PASSWORD", self.POSTGRES_PASSWORD.get_secret_value())
self._check_default_secret("VALKEY_PASSWORD", self.VALKEY_PASSWORD.get_secret_value())

return self

Expand Down
8 changes: 8 additions & 0 deletions backend/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from loguru import logger

from app.api.router import api_router
from app.core.cache import cache
from app.core.config import settings
from app.core.db import db

Expand Down Expand Up @@ -40,6 +41,13 @@ async def lifespan(_: FastAPI) -> AsyncGenerator:
logger.error(f"Error creating first superuser: {e}")
raise e

logger.info("Initializing cache client")
try:
await cache.create_client()
except Exception as e:
logger.error(f"Error creating cache client: {e}")
raise

yield
logger.info("Closing database connection pool")
try:
Expand Down
1 change: 1 addition & 0 deletions backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies = [
"python-multipart==0.0.20",
"uvicorn==0.34.0",
"uvloop==0.21.0",
"valkey==6.0.2",
]

[dependency-groups]
Expand Down
1 change: 1 addition & 0 deletions backend/tests/api/routes/test_health_route.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ async def test_health(test_client):
assert result.status_code == 200
assert result.json()["server"] == "healthy"
assert result.json()["db"] == "healthy"
assert result.json()["cache"] == "healthy"
12 changes: 12 additions & 0 deletions backend/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest
from httpx import ASGITransport, AsyncClient

from app.core.cache import cache
from app.core.config import settings
from app.core.db import db
from app.main import app
Expand Down Expand Up @@ -33,6 +34,17 @@ async def test_db():
await db.close_pool()


@pytest.fixture(autouse=True)
async def test_cache():
await cache.create_client()
yield cache
if cache.client:
await cache.create_client()

await cache.client.flushall() # type: ignore
await cache.close_client()


@pytest.fixture
async def test_client():
async with AsyncClient(
Expand Down
4 changes: 4 additions & 0 deletions backend/tests/core/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ def test_temperature(temperature):
POSTGRES_HOST="some_host",
POSTGRES_USER="pg",
POSTGRES_PASSWORD=SecretStr("pgpassword"),
VALKEY_HOST="valkey",
VALKEY_PASSWORD=SecretStr("valkeypassword"),
OPENAI_API_KEY=SecretStr("some_key"),
TEMPERATURE=temperature,
)
Expand All @@ -30,6 +32,8 @@ def test_invalid_temperature(temperature):
POSTGRES_HOST="some_host",
POSTGRES_USER="pg",
POSTGRES_PASSWORD=SecretStr("pgpassword"),
VALKEY_HOST="valkey",
VALKEY_PASSWORD=SecretStr("valkeypassword"),
OPENAI_API_KEY=SecretStr("some_key"),
TEMPERATURE=temperature,
)
11 changes: 11 additions & 0 deletions backend/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions docker-compose.ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ services:
container_name: backend
depends_on:
- db
- valkey
ports:
- "8000:8000"
environment:
Expand All @@ -16,6 +17,8 @@ services:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=test_password
- POSTGRES_DB=scan
- VALKEY_HOST=127.0.0.1
- VALKEY_PASSWORD=test_password
- OPENAI_API_KEY=someKey
db:
image: postgres:17-alpine
Expand All @@ -30,6 +33,14 @@ services:
volumes:
- db-data:/var/lib/postgresql/data

valkey:
image: valkey/valkey:8-alpine
expose:
- 6379
ports:
- 6379:6379
command: valkey-server --requirepass test_password

volumes:
db-data:

Expand Down
9 changes: 9 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ services:
container_name: backend
depends_on:
- db
- valkey
ports:
- "8000:8000"
env_file:
Expand All @@ -25,6 +26,14 @@ services:
volumes:
- db-data:/var/lib/postgresql/data

valkey:
image: valkey/valkey:8-alpine
expose:
- 6379
ports:
- 6379:6379
command: valkey-server --requirepass test_password

volumes:
db-data:

Expand Down
6 changes: 3 additions & 3 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@
cd frontend && \
npm run start

@fronend-line:
@frontend-lint:
cd frontend && \
npm run lint

@docker-up:
docker compose up
docker compose up --build

@docker-up-backend-dev:
docker compose up db
docker compose up db valkey

@docker-up-detached:
docker compose up -d
Expand Down

0 comments on commit e2b5829

Please sign in to comment.