Mastering the transition from local development to resilient production deployments: container registries, reverse proxies, streaming SSE configurations, health probes, zero-downtime rollouts, secret custody, and AI-specific resource planning outside the localhost sandbox.
Tracing the complete journey of an AI application from a developer workstation to resilient, 24/7 cloud compute.
During local development, your FastAPI AI service runs on localhost:8000. It reads a local .env file, connects to a local SQLite or Dockerized PostgreSQL container, reloads automatically whenever you save a file, and completely terminates whenever you shut your laptop lid.
Production deployment is the operational process of packaging your application into an immutable artifact, provisioning isolated compute resources, binding to dynamic internal networking ports, configuring domain routing over TLS/HTTPS, and ensuring the service automatically self-heals if a worker crashes under high inference load.
Dimension
Local Development
Staging / Preview
Production Environment
Lifecycle
Ephemeral; terminates on laptop sleep
Continuous; rebuilt per pull request (PR)
24/7/365 High Availability with SLAs
Networking
Loopback (127.0.0.1:8000)
Internal VPN or staging subdomain
Public Edge DNS with HTTPS / TLS termination
Configuration
Plaintext .env file on disk
Staging secrets injected via CI/CD
Cloud Secret Manager / KMS encrypted vaults
Data Substrate
Local test database; mock vectors
Sanitized seed data; isolated test tenant
Multi-AZ Managed RDS, S3, & Vector Cluster
AI Provider Keys
Personal dev API keys (low rate limit)
Shared team staging tier with spend limits
Enterprise tier with strict quota alarms
INTERACTIVE LAB 1 OF 7
The End-to-End Deployment Journey Simulator
Click each phase of the promotion pipeline to observe the artifacts, commands, and infrastructure transitions that turn raw Python code into an active production AI service.
1. Git Push
Commit sha: e9a41b2
2. CI/CD Build
Docker Buildx AMD64
3. Registry Push
ghcr.io/acme/api:v1.4
4. Cloud Deploy
Task Definition Rev 14
5. Health Check
GET /ready -> 200 OK
6. Live Traffic
HTTPS api.acme.com
Active Phase: 1. Git PushArtifact: Commit sha: e9a41b2
Developer pushes code to main branch on GitHub / GitLab.
Decomposing the production topology into stateless HTTP compute, persistent storage, asynchronous queues, and monitoring.
Unlike a simple monolith where everything runs in a single process on a single virtual machine, modern AI applications are built on decoupled, specialized infrastructure components. Each component solves a distinct scaling constraint:
1. Edge & Reverse Proxy Stateless
Cloudflare / Nginx / AWS ALB. Terminates SSL/TLS certificates, mitigates DDoS attacks, and routes traffic to backend pools.
2. FastAPI Application Server Stateless
Dockerized container replicas running Uvicorn. Validates tokens, handles SSE streams, and executes business logic.
Durable source of truth for chat sessions & permissions.
4. S3 Object Storageβ
High-durability blob storage for customer PDFs and files.
5. Async Worker & Queueβ
Prevents HTTP 504 timeouts on heavy OCR/chunking tasks.
6. Observability & APMβ
Tracks p95 latency, token spend, and provider error rates.
Deployment Architecture Health Score:100% π‘ PRODUCTION READY
β Excellent! The architecture decouples stateless compute from persistent storage, insulates HTTP threads with background workers, and provides full observability.
03
From Docker Image to Production
Promoting container images through registries, immutable tagging strategies, and multi-architecture builds.
In development, running docker run -p 8000:8000 ai-api builds and runs on your local machine. In production, your local machine does not touch the cloud servers directly. Instead, modern deployments rely on animmutable artifact promotion pipeline:
The Immutable Container Promotion Workflow
1. Multi-Arch Build
CI/CD runner executes docker buildx build --platform linux/amd64to ensure Apple Silicon Macs don't push ARM binaries to x86 cloud servers.
2. Container Registry
Image is pushed to AWS ECR, GitHub Container Registry (GHCR), or Docker Hub with git commit SHA and semantic tags.
3. Orchestrator Pull
Cloud compute nodes (ECS / Cloud Run / K8s) pull the verified image digest over private cloud VPC networking.
4. Container Startup
Orchestrator injects runtime environment variables and starts the container as a non-root user.
The Danger of the :latest Tag
Never deploy with the tag my-image:latest in production. :latest is mutable and can point to different code at different times. Always tag images with the specific Git commit SHA (e.g. ghcr.io/acme/api:sha-9f81a2b) or immutable digest (@sha256:...). This guarantees that rollbacks are 100% reproducible.
04
Environment Configuration & Secrets Management
Twelve-Factor configuration principles, runtime secret injection, and Pydantic startup validation.
According to Twelve-Factor App Principle III, an application's configuration should be strictly separated from code. The exact same Docker image artifact built by CI/CD should run in staging and productionβonly the injected environment variables change.
python / pydantic-settings β Fail-Fast Production Configuration
from pydantic_settings import BaseSettings
class ProductionSettings(BaseSettings):
ai_api_key: str # Crashes on boot if missing!
database_url: str
environment: str = "production"
debug: bool = False # Enforces False in production
settings = ProductionSettings()
INTERACTIVE LAB 3 OF 7
Production Configuration Checker & Patch Lab
Inspect vulnerable production configurations containing leaked keys, loopback host bindings, or connection pool exhaustion. Select the correct Twelve-Factor architectural fix and validate the patch.
Vulnerable Config 1: Production Secrets in Code
Vulnerability: Raw API keys, database passwords, and DEBUG=True are hardcoded in the codebase and committed to Git.
How public HTTP requests navigate from a global domain to an internal container port, and why AI streaming requires specialized reverse proxy tuning.
When a user or client application interacts with your production AI service, they never send requests directly to a raw container IP address. Modern production infrastructure routes requests through an orchestrated ingress pipeline consisting of DNS records, Anycast Edge CDNs, TLS Termination, and Reverse Proxies.
4. ContainerFastAPI Pod :8000Single-Worker Uvicorn
DNS Resolution & Records
The client queries DNS for api.neurochat.io. An A record maps the hostname to an IPv4 address, an AAAA record to IPv6, or a CNAME record aliases the hostname to an ingress load balancer (e.g. AWS ALB or Cloudflare proxy).
TLS / HTTPS Handshake
All public traffic must be encrypted over HTTPS (Port 443). TLS certificates are provisioned automatically via ACME (Let's Encrypt) or platform-managed certificates. The reverse proxy handles cryptographic decryption (TLS termination) so backend containers receive plain HTTP.
β οΈ The AI Reverse Proxy Streaming Buffer Gotcha
Standard reverse proxies (Nginx, Traefik, AWS ALB, Cloudflare) are designed to buffer upstream HTTP responses until the complete payload is received or an internal memory buffer (typically 4KB to 8KB) fills up before flushing bytes to the client.
In an AI application streaming tokens via Server-Sent Events (SSE), response buffering completely destroys the user experience. The client sees zero tokens for 20 seconds, and then suddenly receives all 500 words at once!
Furthermore, standard reverse proxy timeouts are set to 30 to 60 seconds. Complex reasoning models (like o1 or Claude 3.5 Sonnet processing deep chains of thought) frequently exceed 45 seconds before emitting first tokens, triggering HTTP 504 Gateway Timeout errors.
production-nginx-ai.conf (SSE Streaming & Long Timeouts)
Architecting resilient container lifecycles with separate liveness and readiness probes, lifespan context managers, and SIGTERM drain windows.
In production container orchestrators (Kubernetes, AWS ECS, Google Cloud Run, Azure Container Apps), containers are constantly started, health-checked, scaled, and replaced. If your application crashes or locks up, the orchestrator relies on Health Probes to detect failure and execute automated recovery.
Startup Probe
Protects heavy initialization. If your AI backend takes 45 seconds to download embedding weights, initialize vector index caches, and warm database connection pools, the startup probe grants extra leeway before liveness checks kick in.
Liveness Probe (/health/live)
Determines if the container process is alive or deadlocked in an infinite loop. Must be lightweight (returns 200 OK immediately). If this probe fails repeatedly, the orchestrator kills and restarts the container.
Readiness Probe (/health/ready)
Determines if the container is currently capable of servicing live user traffic. Checks database connectivity, Redis connection, and model availability. If this fails, the load balancer removes the container from rotation without killing it.
π‘ Anti-Pattern: Coupling Liveness to External Upstreams
Never check external dependencies (like OpenAI API or external database) inside your /health/live endpoint! If OpenAI experiences a 3-minute degradation, your container liveness probes will fail, causing every single pod in your cluster to enter a cascading restart loop (CrashLoopBackOff). Keep liveness purely local to the process.
import asyncio
from contextlib import asynccontextmanager
from fastapi import FastAPI, Response, status
import asyncpg
import httpx
state = {}
@asynccontextmanager
async def lifespan(app: FastAPI):
# ββ 1. STARTUP: Warm pools & verify upstream credentials ββ
print("[STARTUP] Initializing async PostgreSQL connection pool...")
state["db_pool"] = await asyncpg.create_pool("postgresql://app_user:prod_pass@pg-cluster:5432/neurochat_db")
state["http_client"] = httpx.AsyncClient(timeout=60.0)
state["ready"] = True
print("[STARTUP] All pools initialized. Ready for traffic.")
yield
# ββ 2. SHUTDOWN (SIGTERM received): Graceful drain ββ
print("[SHUTDOWN] SIGTERM caught. Draining in-flight AI streams...")
state["ready"] = False # Immediately fail readiness so LB stops sending new requests
# Allow 15-second drain window for active LLM streaming responses to finish
await asyncio.sleep(15)
# Safely close persistent connection pools
await state["db_pool"].close()
await state["http_client"].aclose()
print("[SHUTDOWN] Clean exit completed.")
app = FastAPI(lifespan=lifespan)
@app.get("/health/live", tags=["Probes"])
async def liveness():
"""Lightweight check: Is process event loop responsive?"""
return {"status": "alive"}
@app.get("/health/ready", tags=["Probes"])
async def readiness(response: Response):
"""Deep check: Are DB pool and resources ready to accept traffic?"""
if not state.get("ready"):
response.status_code = status.HTTP_503_SERVICE_UNAVAILABLE
return {"status": "draining_or_unready"}
try:
async with state["db_pool"].acquire() as conn:
await conn.execute("SELECT 1")
return {"status": "ready", "database": "connected"}
except Exception as e:
response.status_code = status.HTTP_503_SERVICE_UNAVAILABLE
return {"status": "database_error", "detail": str(e)}
07
AI-Specific Resource Planning & OOM Avoidance
Why AI workloads shatter traditional web scaling formulas, and how process worker multiplication triggers catastrophic Linux OOM-Kills.
In standard CRUD web applications, RAM requirements are modest (100β300 MB per container) and CPU is the primary bottleneck under traffic. In AI engineering, memory footprint dominates. Large embedding models, rerankers, tokenizer vocabularies, and KV caches consume massive memory.
β οΈ The FastAPI Multi-Worker Memory Multiplier Trap
In traditional Python deployments, engineers frequently configure Gunicorn or Uvicorn with multiple workers using the formula workers = (2 * CPU_cores) + 1.
If your container loads an in-memory embedding model (e.g. BGE-Large at 1.4 GB) or local reranker, every forked worker process loads its own copy of the model weights into RAM. A 4-worker container requires 4 Γ 1.4 GB = 5.6 GB RAM just for idle model weights, before handling a single request!
Official FastAPI 2026 Production Guidance: Run single-process containers (1 Uvicorn worker per container) and scale horizontally by deploying multiple container replicas across your cluster. This guarantees zero model duplication per container and prevents Linux OOM (Exit code 137).
INTERACTIVE LAB 04
AI Resource Planner & OOM Simulator
Adjust model size, container memory limits, worker processes, and concurrency to observe memory multiplication and Linux OOM crash dynamics.
Scenarios:
1200 MB (1.17 GB)
0 MB for pure OpenAI/Claude proxy; ~1,400 MB for local BGE embedding model.
1 Worker (Recommended)
Multiplies in-memory model weights by process count!
2048 MB (2.0 GB)
Hard memory limit set in Docker Compose or Kubernetes pod spec.
20 Concurrent Streams
Active streaming connections holding tokenizer buffers and context payloads.
Live Resource Calculation
HEALTHY HEADROOM
Base Python Runtime
180 MB
Model Memory (1x)
1200 MB
Stream Context Buffers
240 MB
Total RAM Required
1620 MB (79%)
β Simulation Result: Operating safely within cgroup limits! The container uses 1620 MB with 428 MB of headroom remaining (21% buffer).
08
Stateless vs Stateful AI Deployment
Why production AI containers must be completely disposable, and where state actually lives in modern AI application infrastructure.
In production cloud environments, containers are ephemeral cattle, not pets. An autoscaler can terminate a container when load drops, a node can undergo spot preemption, or a container can crash. If your application saves uploaded user PDFs or conversation history to the local container filesystem (e.g. /app/uploads or ./chat_history.json), that data is permanently vaporized when the container restarts.
Data Category
Anti-Pattern (Stateful Trap)
Production Architecture (Externalized)
Resilience Guarantee
Chat History & Memory
In-memory Python list or local JSON file
PostgreSQL database or DynamoDB
Survives any container restart; queryable by all pods
User Uploaded Documents
Local disk folder (/app/docs/)
S3 / Google Cloud Storage / MinIO bucket
Infinite scale, CDN-compatible, immutable URLs
Vector Embeddings
Local in-memory FAISS index file
Cloud Vector DB (pgvector / Pinecone / Qdrant)
Shared across all replicas with zero indexing rebuilds
Streaming Rate Limits
FastAPI in-memory dictionary
Distributed Redis Cluster with sliding window
Enforced globally across all autoscaled backend pods
Temporary Processing
Hardcoded root directory
Ephemeral /tmp volume (deleted post-task)
Zero persistent dependencies inside container root
π‘ The Golden Test of Stateless AI Architecture
Ask yourself: βIf I run docker rm -f on every running container in my cluster right now, will any customer lose a chat message, an uploaded file, or an embedding vector?β If the answer is yes, you have an un-isolated stateful anti-pattern that must be refactored into external managed storage before deploying to production.
09
Background Jobs & Long-Running AI Workloads
Decoupling heavy AI computations from synchronous HTTP request threads using asynchronous task queues and worker pools.
Standard HTTP requests expect responses within milliseconds or a few seconds. If a user uploads a 100-page PDF document, extracting text, calculating chunk boundaries, generating 2,000 vector embeddings, and indexing them into a vector database can take 45 to 180 seconds.
Running this work directly inside a FastAPI HTTP route handler blocks server threads, ties up reverse proxy connections, and inevitably triggers client or proxy timeouts (HTTP 504). Production AI architectures decouple long-running tasks using the Asynchronous Job Queue Pattern.
Asynchronous AI Job Processing Pipeline
1. ClientPOST /docs/processUpload PDF payload
β
2. API GatewayEnqueue Task & ReturnHTTP 202 Accepted + Job ID
Dispatch heavy AI tasks to an asynchronous background worker pool. Observe status transitions (Queued β Running β Completed) without blocking the API.
Active Job Queue (Redis + ARQ Worker Pool)1 Active Workers Running
Job ID
Task Payload
Status
Processing Time
Worker Action
job_99a1
Document Chunking (40 pages)
completed
4s
β Embeddings indexed in pgvector
job_99a2
Batch Vector Embeddings (1,200 chunks)
running
In flight...
β‘ Worker computing embeddings...
10
Logging, Monitoring & AI Observability
The three layers of production AI telemetry: infrastructure metrics, API performance, and token/cost observability.
Deploying code is only step one. In production, you need continuous visibility to answer three distinct questions:
LAYER 1
βWhat happened?β (Logs)
Structured JSON stdout logs emitted by FastAPI and captured by aggregate log shippers (AWS CloudWatch, Datadog, Grafana Loki). Contains request IDs, model IDs, token counts, and error stack traces.
LAYER 2
βWhat is happening?β (Metrics)
Time-series gauges and counters: Requests per second (RPS), HTTP error rate (4xx/5xx), p50/p95/p99 latency, container CPU/RAM utilization, and upstream rate limit consumption.
LAYER 3
βWhy did it happen?β (Traces)
Distributed OpenTelemetry traces breaking down each request into child spans: Vector DB similarity search latency vs LLM Time-to-First-Token (TTFT) vs stream transmission duration.
INTERACTIVE LAB 06
Production Incident Console & Log Triage
Inspect live synthetic metrics, error rates, and structured log streams to diagnose production outages.
p50 Latency
240ms
p95 Latency
29.8s
p99 Latency
30.0s (TIMEOUT)
Error Rate
34%
# βββ REAL-TIME STDOUT LOG STREAM βββ
[2026-09-20T14:22:01.102Z] INFO [fastapi.ingress] POST /v1/chat/stream req_id=req_88f91 model=claude-3-7-sonnet
[2026-09-20T14:22:31.104Z] ERROR [nginx.proxy] 110: Connection timed out (upstream server didn't respond in 30s) while reading response header from upstream, client: 104.28.14.9, upstream: "http://10.0.4.12:8000/v1/chat/stream"
Reverse proxy 30s timeout cutting off long LLM inference calls. Upstream took 42s.
11
Deployment Strategies & Cloud Platform Selection
Objective comparison of container platforms, serverless runtimes, and GPU clusters based on operational complexity, latency, and cost.
There is no universally βbestβ cloud platform. The optimal deployment target depends directly on whether your application is an API proxy to hosted frontier models or whether you are serving weights on dedicated GPU hardware.
Deployment Model
Platform Examples
Maintenance & Control
Scaling & Latency
Optimal Use Case
Serverless Containers
Google Cloud Run, AWS App Runner, Azure Container Apps
Zero server management; pay-per-request; auto TLS
Scale-to-zero; cold starts (2β5s) if loading heavy models
FastAPI backends using external LLM APIs (OpenAI, Claude, Groq)
Container Orchestrators
AWS ECS / EKS, Google GKE, Kubernetes
High control; requires VPC, Ingress, and IAM configuration
Sub-second horizontal pod autoscaling; zero cold starts
Multi-service AI platforms with private databases and vector DBs
Dedicated GPU Instances
AWS EC2 (G5/P4d), Lambda Labs, RunPod, Vast.ai
Full root control; manual OS and CUDA driver management
Fixed cost; requires model warm-up; manual autoscaling
Fully managed model endpoints; zero GPU operations
Instant token streaming; high concurrency SLAs
Production open-weights inference without managing GPU instances
12
Deployment Failure, Rollback & Automated Recovery
What fails during production rollouts, how rolling updates detect regression, and how to execute automated zero-downtime rollbacks.
Even after passing unit tests locally, production deployments can fail due to environment mismatches, missing secrets, unapplied database migrations, or upstream API changes.
Zero-Downtime Rolling Update & Automated Rollback
Version 1 (Green)Active 3 Replicas100% User Traffic
β
Deploy V2 (Blue)Spawn Pod 1 of V2Health Probe Checking...
β
Probe Fails (503)Missing Secret DetectedV2 Pod Terminated
[FATAL] Container killed by Linux kernel (Exit Code 137)
13
Production AI Deployment Security
Essential deployment-level security practices: least-privilege IAM roles, VPC network segmentation, non-root execution, and log scrubbing.
1. Non-Root Execution (Least Privilege)
Never run production containers as root (UID 0). If a remote code execution vulnerability occurs in an open-source library, the attacker inherits root access. Always declare USER appuser in your multi-stage Dockerfile.
2. Private VPC Network Isolation
Databases (PostgreSQL), Vector DBs (Qdrant), and Cache clusters (Redis) must never have public IP addresses. Place them in private subnets accessible only via internal VPC routing from authorized backend pods.
3. Automated Secret Masking in Logs
AI applications process sensitive data (customer prompts, PII, API tokens). Configure log sanitizers or custom formatters to scrub values matching sk-proj-.* or bearer tokens before writing to stdout.
4. Ephemeral Cloud IAM Credentials
Do not bake static cloud access keys into containers. Use cloud-native identity federation (AWS IRSA, GCP Workload Identity, Azure Managed Identity) to grant short-lived, rotatable STS tokens to running pods.
14
Capstone Mini-Project: Production Deployment Plan
Complete architectural blueprint for deploying an enterprise AI chat application with FastAPI, pgvector, Redis background workers, and S3 object storage.
Review the complete production-grade docker-compose.prod.yml specification below. It brings together every concept from this curriculum: single-process Uvicorn containers, non-root user execution, externalized persistent storage, separate Redis queues for background chunking, reverse proxy with unbuffered SSE streaming, and health checks with automatic restart policies.
Users experienced a 15-second frozen blank screen, followed by all 800 tokens of the LLM response dumping onto the page simultaneously instead of streaming in real time.
Root Cause Analysis:
Nginx reverse proxy had 'proxy_buffering on' by default, which held incoming HTTP chunks until its 16KB memory buffer was full before flushing to the client.
Verified Production Fix:
Disable buffering on streaming routes in Nginx and emit 'X-Accel-Buffering: no' response headers from FastAPI.
#2: Multi-Worker Container Crashes with Linux OOM-Killer
critical
Reported Production Symptom:
FastAPI container was provisioned with 4GB RAM on AWS ECS. Immediately after boot, the container crashed with Exit Code 137 (Out Of Memory).
Root Cause Analysis:
The Dockerfile ran 'gunicorn -w 4 -k uvicorn.workers.UvicornWorker'. Each worker process loaded an in-memory BGE embedding model taking 1.2GB RAM. 4 workers * 1.2GB = 4.8GB RAM, instantly exceeding the 4GB cgroup limit.
Verified Production Fix:
Run 1 process per container using 'fastapi run' or 'uvicorn app.main:app', and scale horizontally via ECS task replicas instead of internal processes.
Remediation Code / Configuration
# β DANGEROUS: Spawns 4 workers inside one container (4x model RAM!)
# CMD ["gunicorn", "app.main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:8000"]
# β PRODUCTION BEST PRACTICE: 1 worker per container, bounded cgroups
# In Dockerfile:
CMD ["fastapi", "run", "app/main.py", "--port", "8000", "--workers", "1"]
# In docker-compose.prod.yml or Kubernetes:
# Scale horizontally with independent 1-process replicas:
# services:
# ai-backend:
# image: ghcr.io/acme/ai-backend:v1.2.0
# deploy:
# replicas: 4
# resources:
# limits:
# memory: 1500M
# cpus: "1.0"
#3: Reverse Proxy 30-Second Timeout Cuts Off Complex Reasoning Models
high
Reported Production Symptom:
When users asked deep analytical questions requiring OpenAI o1 or Claude 3.5 Sonnet thinking steps, the browser threw '504 Gateway Timeout' at exactly 30.0 seconds.
Root Cause Analysis:
The cloud load balancer and ingress reverse proxy had a default 30-second read timeout. Deep reasoning models can take 45β90 seconds to synthesize complex responses.
Verified Production Fix:
Increase load balancer and reverse proxy read/idle timeouts to 180sβ300s for AI inference routes.
Remediation Code / Configuration
# In AWS ALB / Nginx / Traefik:
# Nginx upstream timeout tuning for AI inference
location /api/v1/ai/ {
proxy_pass http://backend_service;
# Increase from default 30s to 300s for reasoning models
proxy_connect_timeout 60s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
# Keep TCP connection alive
proxy_http_version 1.1;
proxy_set_header Connection "";
}
#4: Container Listens on 127.0.0.1: Connection Refused from Load Balancer
critical
Reported Production Symptom:
Docker container deployed successfully and reported running, but cloud health checks failed and users received '502 Bad Gateway'.
Root Cause Analysis:
FastAPI command was executed as 'uvicorn app.main:app --host 127.0.0.1'. It only listened to internal loopback, rejecting external packets routed from the cloud gateway bridge.
Verified Production Fix:
Bind the server to 0.0.0.0 inside the container startup command.
Remediation Code / Configuration
# In Dockerfile:
# β INCORRECT: Only listens to loopback inside container
# CMD ["uvicorn", "app.main:app", "--host", "127.0.0.1", "--port", "8000"]
# β CORRECT: Listens on all interfaces (0.0.0.0)
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
#5: Production Secrets Accidentally Baked into Public Container Image
critical
Reported Production Symptom:
GitGuardian alerted engineering that OPENAI_API_KEY and production PostgreSQL database credentials were leaked on public Docker Hub.
Root Cause Analysis:
The Dockerfile contained 'COPY . .', and '.dockerignore' was missing. The local developer '.env' file was copied into an image layer.
Verified Production Fix:
Add '.env' and local files to '.dockerignore'. Inject production secrets at runtime using container environment variables or cloud secret stores.
Remediation Code / Configuration
# 1. Create .dockerignore in project root
.env
.env.*
!.env.example
__pycache__/
*.pyc
.git/
.github/
venv/
.venv/
node_modules/
# 2. In Dockerfile: Never copy .env
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app/ app/
USER appuser
CMD ["fastapi", "run", "app/main.py", "--port", "8000"]
#6: Missing Readiness Probe Sends Traffic to Cold Container Before DB Sync
high
Reported Production Symptom:
During rolling updates, 2% of user requests received '500 Internal Server Error: Database Connection Not Established'.
Root Cause Analysis:
The cloud platform had only a liveness check, assuming the app was ready as soon as the port opened, before asynchronous database connection pools were initialized.
Verified Production Fix:
Implement a dedicated '/ready' endpoint that validates database and cache connectivity before returning HTTP 200.
#7: Locking Database Migration Freezes Production During Rolling Update
critical
Reported Production Symptom:
Running 'alembic upgrade head' added a non-null column without a default to the 'conversations' table with an exclusive lock, causing all active chat requests to deadlock.
Root Cause Analysis:
Deploying breaking database schema changes during a rolling update when both old and new container versions are running simultaneously.
Verified Production Fix:
Follow Expand-Contract database migration patterns: make new columns nullable or provide server-side defaults; run backwards-compatible migrations before deploying application code.
Remediation Code / Configuration
# Expand-Contract Safe Migration Pattern
# STEP 1: Add new column as NULLABLE (Old code continues working!)
def upgrade():
op.add_column('conversations', sa.Column('model_version', sa.String(64), nullable=True))
# STEP 2: Deploy new application code that writes to 'model_version'
# STEP 3: Backfill existing rows with default value
# STEP 4: Alter column to NOT NULL after deployment completes
def set_not_null_post_deploy():
op.alter_column('conversations', 'model_version', nullable=False)
Users trying to upload 20MB PDF documents to the AI document analyzer received '403 Forbidden: SignatureDoesNotMatch' from Amazon S3.
Root Cause Analysis:
S3 bucket was missing CORS rules for the production frontend domain, and presigned upload URLs were configured with a 30-second TTL that expired before large uploads completed.
Verified Production Fix:
Configure S3 CORS allowing frontend origin and extend presigned upload URL TTL to 15 minutes (900s).