Day 10: Building a Multi‑Container FastAPI App with PostgreSQL, Redis, and Celery
This tutorial extends the previous FastAPI example by adding Redis caching and Celery asynchronous tasks, showing the project layout, a complete docker‑compose configuration, required Python packages, sample FastAPI and Celery worker code, startup commands, health‑check setup, and key takeaways.
Project Structure
project/
├── docker-compose.yml
├── Dockerfile
├── requirements.txt
└── app/
├── __init__.py
├── main.py
└── celery_worker.pydocker-compose.yml
services:
api:
build: .
ports:
- "8000:8000"
environment:
DATABASE_URL: postgresql+asyncpg://app:secret@db:5432/mydb
REDIS_URL: redis://redis:6379/0
CELERY_BROKER_URL: redis://redis:6379/1
CELERY_RESULT_BACKEND: redis://redis:6379/2
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
- ./app:/app
command: ["uvicorn", "app.main:app", "--reload", "--host", "0.0.0.0"]
worker:
build: .
environment:
DATABASE_URL: postgresql+asyncpg://app:secret@db:5432/mydb
REDIS_URL: redis://redis:6379/0
CELERY_BROKER_URL: redis://redis:6379/1
CELERY_RESULT_BACKEND: redis://redis:6379/2
depends_on:
- db
- redis
volumes:
- ./app:/app
command: ["celery", "-A", "app.celery_worker", "worker", "--loglevel=info"]
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: secret
POSTGRES_USER: app
POSTGRES_DB: mydb
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:Code Implementation
requirements.txt
fastapi
uvicorn[standard]
asyncpg
psycopg2-binary
redis
celery
pydantic-settingsapp/main.py
from fastapi import FastAPI
from contextlib import asynccontextmanager
import asyncpg
db_pool = None
@asynccontextmanager
async def lifespan(app: FastAPI):
global db_pool
db_pool = await asyncpg.create_pool("postgresql://app:secret@db:5432/mydb")
yield
await db_pool.close()
app = FastAPI(lifespan=lifespan)
@app.get("/")
async def root():
return {"status": "ok"}app/celery_worker.py
from celery import Celery
celery_app = Celery(
"worker",
broker="redis://redis:6379/1",
backend="redis://redis:6379/2",
)
@celery_app.task
def send_email(to: str):
return {"sent": True, "to": to}Start and Verify
# Start all services
docker compose up -d
# Check service status
docker compose ps
# Test API
curl http://localhost:8000/
# Test Celery task
docker compose exec api python -c "
from app.celery_worker import send_email
result = send_email.delay('[email protected]')
print(result.get(timeout=5))
"Day 10 Summary
Multi‑container orchestration includes api, worker, db, and redis services.
Health checks ensure dependent services are ready before the API starts.
Celery uses Redis as both broker and backend.
The depends_on with condition: service_healthy controls startup order.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Tech Ocean
Focused on AI programming, sharing ready-to-use development efficiency solutions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
