feat: add PostgreSQL and Valkey configuration with async support, enhance database management

This commit is contained in:
2026-06-12 20:05:45 +08:00
parent 1e206eed8b
commit 55b5a18b90
6 changed files with 137 additions and 2 deletions
+6
View File
@@ -7,3 +7,9 @@ LLM_API_KEY=
# Logfire observability (set your token to enable)
LOGFIRE_TOKEN=
# PostgreSQL (asyncpg connection string)
DATABASE_URL=postgresql+asyncpg://agent_alpha:agent_alpha@localhost:5432/agent_alpha
# Valkey / Redis
VALKEY_URL=redis://localhost:6379/0
+4 -1
View File
@@ -10,6 +10,7 @@ from fastapi.middleware.cors import CORSMiddleware
from uvicorn.logging import DefaultFormatter
from backend.core.config import Settings
from backend.core.database import close_engine, close_valkey
from backend.core.dependencies import get_agent_service
from backend.routes.chat import router as chat_router
from backend.routes.health import router as health_router
@@ -81,7 +82,9 @@ class AppBuilder:
# Graceful teardown on shutdown.
await agent_service.shutdown()
logger.info("Agent Alpha backend shuttingdown")
await close_valkey()
await close_engine()
logger.info("Agent Alpha backend shutting down")
# ---------------------------------------------------------------------------
+3
View File
@@ -25,6 +25,9 @@ class Settings(BaseSettings):
llm_api_key: str = ""
logfire_token: str = ""
database_url: str = "postgresql+asyncpg://agent_alpha:agent_alpha@localhost:5432/agent_alpha"
valkey_url: str = "redis://localhost:6379/0"
# ── Factories ──────────────────────────────────────────────────────────
@classmethod
+77
View File
@@ -0,0 +1,77 @@
"""Async SQLAlchemy engine & session factory for PostgreSQL, plus a Valkey client.
Usage::
from backend.core.database import get_session, get_valkey
async with get_session() as session:
result = await session.execute(text("SELECT 1"))
valkey = await get_valkey()
await valkey.set("key", "value")
"""
from __future__ import annotations
from typing import AsyncIterator
from redis.asyncio import Redis
from sqlalchemy.ext.asyncio import (
AsyncSession,
async_sessionmaker,
create_async_engine,
)
from backend.core.config import settings
# ── PostgreSQL (SQLAlchemy async) ──────────────────────────────────────────
_engine = create_async_engine(
settings.database_url,
pool_size=5,
max_overflow=10,
echo=False,
)
_session_factory = async_sessionmaker(
bind=_engine,
class_=AsyncSession,
expire_on_commit=False,
)
async def get_session() -> AsyncIterator[AsyncSession]:
"""Yield an async SQLAlchemy session (for FastAPI dependency injection)."""
async with _session_factory() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
# ── Valkey (Redis-compatible) ─────────────────────────────────────────────
_valkey: Redis | None = None
async def get_valkey() -> Redis:
"""Return a shared Valkey (Redis) async client connection."""
global _valkey
if _valkey is None:
_valkey = Redis.from_url(settings.valkey_url, decode_responses=True)
return _valkey
async def close_valkey() -> None:
"""Close the Valkey connection pool (call on shutdown)."""
global _valkey
if _valkey is not None:
await _valkey.aclose()
_valkey = None
async def close_engine() -> None:
"""Dispose the SQLAlchemy engine (call on shutdown)."""
await _engine.dispose()
+44 -1
View File
@@ -23,7 +23,14 @@ services:
environment:
- 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}
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
valkey:
condition: service_healthy
# Uncomment to use a local .env file instead of env vars:
# env_file:
# - .env
@@ -42,6 +49,40 @@ services:
- backend
restart: unless-stopped
# ── PostgreSQL ──────────────────────────────────────────────────
postgres:
image: postgres:16-alpine
container_name: agent-alpha-postgres
ports:
- "5432:5432"
environment:
POSTGRES_USER: agent_alpha
POSTGRES_PASSWORD: agent_alpha
POSTGRES_DB: agent_alpha
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U agent_alpha -d agent_alpha"]
interval: 5s
timeout: 5s
retries: 10
restart: unless-stopped
# ── Valkey (Redis-compatible) ──────────────────────────────────
valkey:
image: valkey/valkey:8-alpine
container_name: agent-alpha-valkey
ports:
- "6379:6379"
volumes:
- valkey_data:/data
healthcheck:
test: ["CMD", "valkey-cli", "ping"]
interval: 5s
timeout: 5s
retries: 10
restart: unless-stopped
# ── Ollama (optional — uncomment to run the LLM locally) ────────
# ollama:
# image: ollama/ollama:latest
@@ -59,5 +100,7 @@ services:
# count: all
# capabilities: [gpu]
# volumes:
volumes:
postgres_data:
valkey_data:
# ollama_data:
+3
View File
@@ -16,4 +16,7 @@ dependencies = [
"pydantic-ai-todo>=0.2.4",
"pydantic-deep>=0.3.28",
"uvicorn[standard]>=0.34.0",
"asyncpg>=0.30.0",
"redis[hiredis]>=5.2.0",
"sqlalchemy[asyncio]>=2.0.36",
]