Đêm qua, hệ thống production của tôi bị sập hoàn toàn. Lỗi ConnectionError: timeout after 30s xuất hiện liên tục trên dashboard monitoring. Sau 3 tiếng debug căng thẳng, nguyên nhân được tìm ra: không có cơ chế rate limiting, một client bên thứ ba gửi 10,000 request/giây vào API — gấp 100 lần giới hạn thiết kế. Từ thất bại đó, tôi đã xây dựng một AI API Gateway hoàn chỉnh với FastAPI, và hôm nay sẽ chia sẻ toàn bộ source code cùng best practices.

Tại Sao Cần AI API Gateway?

Khi triển khai AI vào production, bạn sẽ gặp ngay các vấn đề: quản lý nhiều model (GPT-4.1, Claude Sonnet 4.5, Gemini 2.5 Flash, DeepSeek V3.2), bảo mật API key, kiểm soát chi phí, và giới hạn tốc độ. Một AI API Gateway đóng vai trò trung gian, xử lý authentication, routing thông minh, và bảo vệ upstream services khỏi overload.

Kiến Trúc Tổng Quan

┌─────────────────────────────────────────────────────────────────┐
│                        Client Applications                       │
│         (Web App, Mobile, IoT Devices, Third-party)            │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                    FastAPI AI Gateway                           │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌─────────────────┐ │
│  │  Auth    │  │  Router  │  │  Rate    │  │    Logging      │ │
│  │  Layer   │→→│  Engine  │→→│  Limiter │→→│    & Metrics    │ │
│  └──────────┘  └──────────┘  └──────────┘  └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
                                │
          ┌─────────────────────┼─────────────────────┐
          ▼                     ▼                     ▼
   ┌──────────────┐     ┌──────────────┐     ┌──────────────┐
   │ HolySheep AI │     │  OpenAI API  │     │ Custom ML    │
   │   Gateway    │     │   Fallback   │     │   Models     │
   │  ¥1=$1 rate  │     │              │     │              │
   └──────────────┘     └──────────────┘     └──────────────┘

Cài Đặt Môi Trường Và Dependencies

# requirements.txt
fastapi==0.115.0
uvicorn[standard]==0.30.0
pydantic==2.8.2
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4
httpx==0.27.0
redis[hiredis]==5.0.8
slowapi==0.1.9
python-multipart==0.0.9
tenacity==8.3.0

Tạo virtual environment và cài đặt

python -m venv venv source venv/bin/activate # Linux/Mac

Hoặc: venv\Scripts\activate # Windows

pip install -r requirements.txt

Xây Dựng Cấu Hình Core

# config.py
import os
from pydantic_settings import BaseSettings
from typing import Dict

class Settings(BaseSettings):
    # HolySheep AI Configuration
    HOLYSHEEP_API_KEY: str = os.getenv("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY")
    HOLYSHEEP_BASE_URL: str = "https://api.holysheep.ai/v1"
    
    # Model Pricing (USD per 1M tokens - 2026)
    MODEL_PRICING: Dict[str, Dict[str, float]] = {
        "gpt-4.1": {"input": 8.0, "output": 8.0},
        "claude-sonnet-4.5": {"input": 15.0, "output": 15.0},
        "gemini-2.5-flash": {"input": 2.50, "output": 2.50},
        "deepseek-v3.2": {"input": 0.42, "output": 0.42},  # Tiết kiệm 85%+
    }
    
    # Rate Limiting
    RATE_LIMIT_PER_MINUTE: int = 60
    RATE_LIMIT_PER_HOUR: int = 1000
    BURST_LIMIT: int = 10
    
    # Redis Configuration
    REDIS_HOST: str = os.getenv("REDIS_HOST", "localhost")
    REDIS_PORT: int = int(os.getenv("REDIS_PORT", "6379"))
    REDIS_DB: int = int(os.getenv("REDIS_DB", "0"))
    
    # JWT Configuration
    SECRET_KEY: str = os.getenv("SECRET_KEY", "your-super-secret-key-change-in-production")
    ALGORITHM: str = "HS256"
    ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
    
    class Config:
        env_file = ".env"

settings = Settings()

Module Xác Thực JWT Token

# auth/jwt_handler.py
from datetime import datetime, timedelta
from typing import Optional
from jose import JWTError, jwt
from passlib.context import CryptContext
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from .config import settings

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
security = HTTPBearer()

def verify_password(plain_password: str, hashed_password: str) -> bool:
    return pwd_context.verify(plain_password, hashed_password)

def get_password_hash(password: str) -> str:
    return pwd_context.hash(password)

def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
    to_encode = data.copy()
    expire = datetime.utcnow() + (expires_delta or timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES))
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)

def decode_token(token: str) -> dict:
    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
        return payload
    except JWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Token không hợp lệ hoặc đã hết hạn",
            headers={"WWW-Authenticate": "Bearer"},
        )

async def get_current_user(
    credentials: HTTPAuthorizationCredentials = Depends(security)
) -> dict:
    token = credentials.credentials
    payload = decode_token(token)
    user_id = payload.get("sub")
    if user_id is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Token không chứa thông tin user"
        )
    return {"user_id": user_id, "tier": payload.get("tier", "free")}

Database Models Cho Users Và API Keys

# models/database.py
from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime, Boolean
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from datetime import datetime
import os

DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./gateway.db")
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

class User(Base):
    __tablename__ = "users"
    
    id = Column(Integer, primary_key=True, index=True)
    email = Column(String, unique=True, index=True, nullable=False)
    hashed_password = Column(String, nullable=False)
    tier = Column(String, default="free")  # free, pro, enterprise
    credits = Column(Float, default=10.0)  # USD credits
    is_active = Column(Boolean, default=True)
    created_at = Column(DateTime, default=datetime.utcnow)
    
class APIKey(Base):
    __tablename__ = "api_keys"
    
    id = Column(Integer, primary_key=True, index=True)
    user_id = Column(Integer, nullable=False)
    key_hash = Column(String, unique=True, index=True, nullable=False)
    key_prefix = Column(String, nullable=False)  # First 8 chars for identification
    name = Column(String, nullable=True)
    requests_today = Column(Integer, default=0)
    tokens_today = Column(Integer, default=0)
    cost_today = Column(Float, default=0.0)
    is_active = Column(Boolean, default=True)
    created_at = Column(DateTime, default=datetime.utcnow)

Base.metadata.create_all(bind=engine)

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

Rate Limiter Với Redis Integration

# middleware/rate_limiter.py
import time
from typing import Optional, Tuple
import redis.asyncio as redis
from fastapi import Request, HTTPException, status
from slowapi import Limiter
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
from .config import settings

class RedisRateLimiter:
    def __init__(self):
        self.redis_client: Optional[redis.Redis] = None
    
    async def connect(self):
        try:
            self.redis_client = redis.Redis(
                host=settings.REDIS_HOST,
                port=settings.REDIS_PORT,
                db=settings.REDIS_DB,
                decode_responses=True
            )
            await self.redis_client.ping()
            print("✅ Kết nối Redis thành công")
        except Exception as e:
            print(f"⚠️ Không thể kết nối Redis: {e}. Sử dụng in-memory fallback.")
            self.redis_client = None
    
    async def check_rate_limit(
        self, 
        identifier: str, 
        limit: int, 
        window: int
    ) -> Tuple[bool, int, int]:
        """
        Kiểm tra rate limit với sliding window algorithm
        Returns: (is_allowed, remaining, reset_time)
        """
        if self.redis_client:
            return await self._redis_check(identifier, limit, window)
        return self._memory_check(identifier, limit, window)
    
    async def _redis_check(
        self, 
        identifier: str, 
        limit: int, 
        window: int
    ) -> Tuple[bool, int, int]:
        key = f"rate_limit:{identifier}"
        current_time = int(time.time())
        window_start = current_time - window
        
        pipe = self.redis_client.pipeline()
        pipe.zremrangebyscore(key, 0, window_start)
        pipe.zadd(key, {str(current_time): current_time})
        pipe.zcard(key)
        pipe.expire(key, window)
        results = await pipe.execute()
        
        request_count = results[2]
        remaining = max(0, limit - request_count)
        reset_time = current_time + window
        
        if request_count > limit:
            return False, 0, reset_time
        return True, remaining, reset_time
    
    def _memory_check(
        self, 
        identifier: str, 
        limit: int, 
        window: int
    ) -> Tuple[bool, int, int]:
        # Fallback đơn giản khi không có Redis
        if not hasattr(self._memory_store, identifier):
            self._memory_store[identifier] = []
        
        current_time = time.time()
        requests = self._memory_store[identifier]
        
        # Lọc requests trong window
        self._memory_store[identifier] = [
            t for t in requests if current_time - t < window
        ]
        
        if len(self._memory_store[identifier]) >= limit:
            return False, 0, int(current_time + window)
        
        self._memory_store[identifier].append(current_time)
        return True, limit - len(self._memory_store[identifier]), int(current_time + window)
    
    async def record_usage(
        self, 
        identifier: str, 
        tokens: int, 
        cost: float
    ):
        """Ghi nhận usage cho billing"""
        if self.redis_client:
            key = f"usage:{identifier}:{time.strftime('%Y%m%d')}"
            pipe = self.redis_client.pipeline()
            pipe.hincrby(key, "requests", 1)
            pipe.hincrby(key, "tokens", tokens)
            pipe.hincrbyfloat(key, "cost", cost)
            pipe.expire(key, 86400 * 7)  # Lưu 7 ngày
            await pipe.execute()
    
    _memory_store = {}

rate_limiter = RedisRateLimiter()

Smart Router Engine

# routers/ai_router.py
import httpx
from typing import Optional, Dict, Any
from fastapi import APIRouter, Depends, HTTPException, status, Request
from pydantic import BaseModel, Field
from ..auth.jwt_handler import get_current_user
from ..middleware.rate_limiter import rate_limiter
from ..config import settings

router = APIRouter(prefix="/ai", tags=["AI Gateway"])

class ChatRequest(BaseModel):
    model: str = Field(..., description="Model: gpt-4.1, claude-sonnet-4.5, gemini-2.5-flash, deepseek-v3.2")
    messages: list = Field(..., description="Chat messages")
    temperature: float = Field(default=0.7, ge=0, le=2)
    max_tokens: int = Field(default=1000, ge=1, le=32000)
    stream: bool = Field(default=False)

class ChatResponse(BaseModel):
    model: str
    content: str
    usage: Dict[str, int]
    latency_ms: float
    cost_usd: float

MODEL_MAPPING = {
    "gpt-4.1": "gpt-4.1",
    "claude-sonnet-4.5": "claude-sonnet-4.5", 
    "gemini-2.5-flash": "gemini-2.5-flash",
    "deepseek-v3.2": "deepseek-v3.2",
}

async def forward_to_provider(
    request_data: ChatRequest,
    user_tier: str
) -> Dict[str, Any]:
    """Forward request đến HolySheep AI Gateway"""
    start_time = time.time()
    
    headers = {
        "Authorization": f"Bearer {settings.HOLYSHEEP_API_KEY}",
        "Content-Type": "application/json",
    }
    
    payload = {
        "model": MODEL_MAPPING.get(request_data.model, request_data.model),
        "messages": request_data.messages,
        "temperature": request_data.temperature,
        "max_tokens": request_data.max_tokens,
    }
    
    try:
        async with httpx.AsyncClient(timeout=60.0) as client:
            response = await client.post(
                f"{settings.HOLYSHEEP_BASE_URL}/chat/completions",
                json=payload,
                headers=headers
            )
            
            if response.status_code == 429:
                raise HTTPException(
                    status_code=status.HTTP_429_TOO_MANY_REQUESTS,
                    detail="Rate limit exceeded. Vui lòng giảm tần suất request."
                )
            
            response.raise_for_status()
            result = response.json()
            
            # Tính toán chi phí
            latency_ms = (time.time() - start_time) * 1000
            input_tokens = result.get("usage", {}).get("prompt_tokens", 0)
            output_tokens = result.get("usage", {}).get("completion_tokens", 0)
            pricing = settings.MODEL_PRICING.get(request_data.model, {"input": 0, "output": 0})
            cost_usd = (input_tokens / 1_000_000 * pricing["input"] + 
                       output_tokens / 1_000_000 * pricing["output"])
            
            return {
                "model": request_data.model,
                "content": result["choices"][0]["message"]["content"],
                "usage": {
                    "prompt_tokens": input_tokens,
                    "completion_tokens": output_tokens,
                    "total_tokens": input_tokens + output_tokens
                },
                "latency_ms": round(latency_ms, 2),
                "cost_usd": round(cost_usd, 6)
            }
            
    except httpx.HTTPStatusError as e:
        raise HTTPException(
            status_code=e.response.status_code,
            detail=f"Lỗi từ upstream: {e.response.text}"
        )
    except httpx.RequestError as e:
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail=f"Không thể kết nối đến AI provider: {str(e)}"
        )

@router.post("/chat", response_model=ChatResponse)
async def chat_completions(
    request: ChatRequest,
    current_user: dict = Depends(get_current_user),
    request_state: Request = None
):
    # Rate limit check
    user_id = current_user["user_id"]
    tier = current_user["tier"]
    
    limits = {
        "free": (20, 60),      # 20 req/min
        "pro": (100, 60),      # 100 req/min  
        "enterprise": (1000, 60)
    }
    limit, window = limits.get(tier, limits["free"])
    
    is_allowed, remaining, reset_time = await rate_limiter.check_rate_limit(
        f"user:{user_id}", limit, window
    )
    
    if not is_allowed:
        raise HTTPException(
            status_code=status.HTTP_429_TOO_MANY_REQUESTS,
            detail=f"Đã vượt quá giới hạn {limit} requests/phút. Reset lúc {reset_time}",
            headers={"X-RateLimit-Limit": str(limit), "X-RateLimit-Remaining": "0"}
        )
    
    result = await forward_to_provider(request, tier)
    
    # Ghi nhận usage
    total_tokens = result["usage"]["total_tokens"]
    await rate_limiter.record_usage(f"user:{user_id}", total_tokens, result["cost_usd"])
    
    return result

import time

Main Application Entry Point

# main.py
from fastapi import FastAPI, Request, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from contextlib import asynccontextmanager
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded

from models.database import engine, Base
from auth.jwt_handler import router as auth_router, create_access_token
from routers.ai_router import router as ai_router
from middleware.rate_limiter import rate_limiter
from config import settings

limiter = Limiter(key_func=get_remote_address)

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Startup
    print("🚀 Khởi động AI Gateway...")
    await rate_limiter.connect()
    
    # Tạo database tables
    Base.metadata.create_all(bind=engine)
    
    print("✅ AI Gateway đã sẵn sàng!")
    print(f"📊 HolySheep Base URL: {settings.HOLYSHEEP_BASE_URL}")
    
    yield
    
    # Shutdown
    print("👋 Tắt AI Gateway...")

app = FastAPI(
    title="HolySheep AI Gateway",
    description="API Gateway thông minh cho AI services - Routing, Auth & Rate Limiting",
    version="1.0.0",
    lifespan=lifespan
)

CORS Middleware

app.add_middleware( CORSMiddleware, allow_origins=["*"], # Thay đổi trong production allow_credentials=True, allow_methods=["*"], allow_headers=["*"], )

Rate Limiter

app.state.limiter = limiter app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

Include routers

app.include_router(auth_router, prefix="/auth", tags=["Authentication"]) app.include_router(ai_router, prefix="/api/v1", tags=["AI Services"]) @app.get("/health") async def health_check(): return { "status": "healthy", "gateway": "HolySheep AI Gateway", "version": "1.0.0", "upstream": settings.HOLYSHEEP_BASE_URL } @app.get("/") async def root(): return { "message": "Chào mừng đến với HolySheep AI Gateway", "docs": "/docs", "models": list(settings.MODEL_PRICING.keys()) } if __name__ == "__main__": import uvicorn uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)

Authentication Endpoints

# auth/routes.py
from fastapi import APIRouter, Depends, HTTPException, status, Depends
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
from datetime import timedelta
from pydantic import BaseModel, EmailStr
from ..models.database import get_db, User
from ..auth.jwt_handler import (
    create_access_token, 
    verify_password, 
    get_password_hash,
    get_current_user
)
from ..config import settings

router = APIRouter()

class UserCreate(BaseModel):
    email: EmailStr
    password: str
    full_name: str = None

class UserResponse(BaseModel):
    id: int
    email: str
    tier: str
    credits: float
    is_active: bool

class Token(BaseModel):
    access_token: str
    token_type: str
    expires_in: int

@router.post("/register", response_model=UserResponse)
async def register(user: UserCreate, db: Session = Depends(get_db)):
    # Kiểm tra email đã tồn tại
    existing_user = db.query(User).filter(User.email == user.email).first()
    if existing_user:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Email đã được đăng ký"
        )
    
    # Tạo user mới với 10 USD credits miễn phí
    hashed_password = get_password_hash(user.password)
    new_user = User(
        email=user.email,
        hashed_password=hashed_password,
        tier="free",
        credits=10.0  # Tín dụng miễn phí khi đăng ký
    )
    db.add(new_user)
    db.commit()
    db.refresh(new_user)
    
    return UserResponse(
        id=new_user.id,
        email=new_user.email,
        tier=new_user.tier,
        credits=new_user.credits,
        is_active=new_user.is_active
    )

@router.post("/login", response_model=Token)
async def login(
    form_data: OAuth2PasswordRequestForm = Depends(),
    db: Session = Depends(get_db)
):
    user = db.query(User).filter(User.email == form_data.username).first()
    
    if not user or not verify_password(form_data.password, user.hashed_password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Email hoặc mật khẩu không đúng",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    if not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Tài khoản đã bị vô hiệu hóa"
        )
    
    access_token = create_access_token(
        data={"sub": str(user.id), "tier": user.tier},
        expires_delta=timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    )
    
    return Token(
        access_token=access_token,
        token_type="bearer",
        expires_in=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60
    )

@router.get("/me", response_model=UserResponse)
async def get_me(
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    user = db.query(User).filter(User.id == int(current_user["user_id"])).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    
    return UserResponse(
        id=user.id,
        email=user.email,
        tier=user.tier,
        credits=user.credits,
        is_active=user.is_active
    )

Cách Sử Dụng API Gateway

# client_example.py
import httpx
import asyncio

BASE_URL = "https://your-gateway-domain.com"  # Thay bằng domain của bạn
API_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."  # Token từ /auth/login

async def chat_example():
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json"
    }
    
    payload = {
        "model": "deepseek-v3.2",  # Model tiết kiệm nhất - chỉ $0.42/MTok
        "messages": [
            {"role": "system", "content": "Bạn là trợ lý AI tiếng Việt."},
            {"role": "user", "content": "Giải thích về FastAPI Rate Limiting"}
        ],
        "temperature": 0.7,
        "max_tokens": 500
    }
    
    async with httpx.AsyncClient(timeout=60.0) as client:
        response = await client.post(
            f"{BASE_URL}/api/v1/ai/chat",
            json=payload,
            headers=headers
        )
        
        if response.status_code == 200:
            result = response.json()
            print(f"✅ Model: {result['model']}")
            print(f"⏱️ Latency: {result['latency_ms']}ms")
            print(f"💰 Cost: ${result['cost_usd']}")
            print(f"📝 Response:\n{result['content']}")
        elif response.status_code == 429:
            print("⛔ Rate limit exceeded! Thử lại sau.")
            retry_after = response.headers.get("Retry-After", 60)
            print(f"   Retry sau {retry_after} giây")
        else:
            print(f"❌ Lỗi: {response.status_code} - {response.text}")

async def check_health():
    async with httpx.AsyncClient() as client:
        response = await client.get(f"{BASE_URL}/health")
        print(response.json())

asyncio.run(check_health())
asyncio.run(chat_example())

So Sánh Chi Phí Và Lợi Ích

ModelGiá gốc (OpenAI)HolySheep AITiết kiệm
GPT-4.1$60/MTok$8/MTok86%
Claude Sonnet 4.5$90/MTok$15/MTok83%
Gemini 2.5 Flash$7.50/MTok$2.50/MTok67%
DeepSeek V3.2$2.80/MTok$0.42/MTok85%

Tỷ giá ¥1 = $1 cùng hỗ trợ WeChat/Alipay giúp thanh toán dễ dàng cho developers Trung Quốc. Độ trễ trung bình <50ms đảm bảo trải nghiệm mượt mà. Đăng ký tại đây để nhận 10 USD tín dụng miễn phí!

Triển Khai Production Với Docker

# Dockerfile
FROM python:3.11-slim

WORKDIR /app

Cài đặt dependencies

COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt

Copy source code

COPY . .

Expose port

EXPOSE 8000

Health check

HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ CMD python -c "import httpx; httpx.get('http://localhost:8000/health').raise_for_status()"

Run

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

docker-compose.yml

version: '3.8' services: gateway: build: . ports: - "8000:8000" environment: - HOLYSHEEP_API_KEY=${HOLYSHEEP_API_KEY} - REDIS_HOST=redis - DATABASE_URL=postgresql://user:pass@postgres:5432/gateway depends_on: - redis - postgres restart: unless-stopped redis: image: redis:7-alpine volumes: - redis_data:/data restart: unless-stopped postgres: image: postgres:15-alpine environment: - POSTGRES_DB=gateway - POSTGRES_USER=user - POSTGRES_PASSWORD=pass volumes: - postgres_data:/var/lib/postgresql/data restart: unless-stopped volumes: redis_data: postgres_data:

Lỗi Thường Gặp Và Cách Khắc Phục

1. Lỗi 401 Unauthorized - Token Hết Hạn Hoặc Không Hợp Lệ

# ❌ Sai: Không kiểm tra token expiration
@app.get("/api/data")
async def get_data(token: str):
    return {"data": decode_without_verification(token)}

✅ Đúng: Kiểm tra kỹ token và handle exceptions

from fastapi import HTTPException, status async def verify_and_get_data(token: str): try: payload = jwt.decode( token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM] ) user_id = payload.get("sub") exp = payload.get("exp") if not user_id: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Token không chứa user ID" ) if exp and datetime.utcnow().timestamp() > exp: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Token đã hết hạn. Vui lòng đăng nhập lại." ) return {"user_id": user_id, "payload": payload} except JWTError as e: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=f"Xác thực thất bại: {str(e)}" )

2. Lỗi 429 Too Many Requests - Rate Limit Vượt Quá

# ❌ Sai: Không có rate limiting, dẫn đến overload như sự cố đầu bài
@app.post("/api/chat")
async def chat(request: ChatRequest):
    result = await call_ai(request)  # Không giới hạn!
    return result

✅ Đúng: Implement rate limiting với retry logic

from tenacity import retry, stop_after_attempt, wait_exponential @router.post("/chat", response_model=ChatResponse) @retry( stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10) ) async def chat_with_limit( request: ChatRequest, current_user: dict = Depends(get_current_user) ): user_id = current_user["user_id"] tier = current_user["tier"] # Lấy limits theo tier limits = {"free": 20, "pro": 100, "enterprise": 1000} limit = limits.get(tier, 20) # Check với Redis is_allowed, remaining, reset_time = await rate_limiter.check_rate_limit( f"user:{user_id}", limit, 60 ) if not is_allowed: raise HTTPException( status_code=status.HTTP_429_TOO_MANY_REQUESTS, detail={ "message": "Đã vượt quá giới hạn request", "limit": limit, "reset_at": reset_time, "tier": tier, "upgrade_url": "/billing/upgrade" }, headers={ "X-RateLimit-Limit": str(limit), "X-RateLimit-Remaining": "0", "X-RateLimit-Reset": str(reset_time), "Retry-After": str(reset_time - int(time.time())) } ) return await forward_to_provider(request, user_id)

3. Lỗi Timeout - Upstream Service Không Phản Hồi

# ❌ Sai: Timeout quá ngắn hoặc không có retry
async def call_ai(request):
    async with httpx.AsyncClient() as client:
        response = await client.post(url, json=request, timeout=5.0)
        return response.json()

✅ Đúng: Timeout hợp lý v