บทนำ: บทเรียนจาก Production ที่ล่มไป 3 วัน

เมื่อเดือนที่แล้ว ผมเพิ่งผ่านประสบการณ์ที่ไม่อยากจดจำ — ระบบ AI API ที่พัฒนามา 3 เดือนล่มในวันแรกที่ปล่อย production เพราะข้อผิดพลาดเดียว:
ConnectionError: HTTPSConnectionPool(host='api.holysheep.ai', port=443): Max retries exceeded with url: /v1/chat/completions (Caused by NewConnectionError: '<urllib3.connection.HTTPSConnection object at 0x7f8a2c3d4b50>: Failed to establish a new connection: [Errno 110] Connection timed out'))
หลังจากแก้ปัญหาและทำ post-mortem ผมได้ compile "checklist 20 ข้อ" ที่ทุกครั้งก่อน deploy ต้องผ่านทุกข้อ ---

1. ตรวจสอบ API Key และ Environment Variables

# ✅ วิธีที่ถูกต้อง — ใช้ environment variable
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ.get("HOLYSHEEP_API_KEY"),  # ห้าม hardcode!
    base_url="https://api.holysheep.ai/v1"
)

ตรวจสอบว่า key ถูกตั้งค่าหรือไม่

if not os.environ.get("HOLYSHEEP_API_KEY"): raise ValueError("HOLYSHEEP_API_KEY environment variable is not set")
# ❌ วิธีที่ผิด — hardcode key โดยตรง (อันตรายมาก!)
API_KEY = "sk-holysheep-xxxxx"  # เปิดเผยบน GitHub = ถูกลักลอบใช้ทันที

✅ ใช้ .env file + python-dotenv

.env

HOLYSHEEP_API_KEY=sk-holysheep-xxxxx

HOLYSHEEP_BASE_URL=https://api.holysheep.ai/v1

---

2. Timeout Configuration ที่เหมาะสม

import httpx
from openai import OpenAI

client = OpenAI(
    api_key=os.environ.get("HOLYSHEEP_API_KEY"),
    base_url="https://api.holysheep.ai/v1",
    http_client=httpx.Client(
        timeout=httpx.Timeout(60.0, connect=10.0)  # total=60s, connect=10s
    )
)

หรือใช้ async สำหรับ high-concurrency

async_client = OpenAI( api_key=os.environ.get("HOLYSHEEP_API_KEY"), base_url="https://api.holysheep.ai/v1", http_client=httpx.AsyncClient( timeout=httpx.Timeout(60.0, connect=10.0) ) )
**ค่าแนะนำ:** - **Connect timeout**: 5-10 วินาที (ป้องกัน hang ตอน connection) - **Read timeout**: 60-120 วินาที (สำหรับ LLM response ที่อาจใช้เวลา) - **Total timeout**: 120 วินาทีสำหรับ streaming ---

3. Retry Logic ที่มี Exponential Backoff

import time
import httpx
from openai import APIError, RateLimitError, APITimeoutError

def call_with_retry(client, messages, max_retries=3):
    """เรียก API พร้อม retry logic แบบ exponential backoff"""
    
    for attempt in range(max_retries):
        try:
            response = client.chat.completions.create(
                model="gpt-4.1",
                messages=messages,
                timeout=60.0
            )
            return response
            
        except RateLimitError:
            # HolySheep มี rate limit — รอก่อน retry
            wait_time = 2 ** attempt + 0.5  # 2.5s, 4.5s, 8.5s
            print(f"Rate limited, waiting {wait_time}s...")
            time.sleep(wait_time)
            
        except APITimeoutError:
            wait_time = 2 ** attempt
            print(f"Timeout, retrying in {wait_time}s...")
            time.sleep(wait_time)
            
        except APIError as e:
            if e.status_code in [500, 502, 503, 504]:
                # Server error — retry ได้
                wait_time = 2 ** attempt
                print(f"Server error {e.status_code}, retrying...")
                time.sleep(wait_time)
            else:
                # Client error — ไม่ควร retry
                raise
                
    raise Exception(f"Failed after {max_retries} retries")
---

4. Rate Limit Handling

import time
from collections import defaultdict
from threading import Lock

class RateLimiter:
    """Token bucket rate limiter สำหรับ HolySheep API"""
    
    def __init__(self, requests_per_minute=60):
        self.requests_per_minute = requests_per_minute
        self.requests = []
        self.lock = Lock()
    
    def acquire(self):
        with self.lock:
            now = time.time()
            # ลบ request ที่เก่ากว่า 1 นาที
            self.requests = [t for t in self.requests if now - t < 60]
            
            if len(self.requests) >= self.requests_per_minute:
                sleep_time = 60 - (now - self.requests[0])
                print(f"Rate limit reached, sleeping {sleep_time:.1f}s")
                time.sleep(sleep_time)
                return self.acquire()  # retry
            
            self.requests.append(now)

ใช้งาน

limiter = RateLimiter(requests_per_minute=60) def send_request(): limiter.acquire() # รอจนกว่าจะพร้อม return client.chat.completions.create( model="gpt-4.1", messages=[{"role": "user", "content": "Hello"}] )
---

5. Input Validation ก่อนส่งไป API

from pydantic import BaseModel, Field, validator
from typing import Optional

class ChatRequest(BaseModel):
    model: str = Field(default="gpt-4.1")
    messages: list = Field(min_length=1)
    temperature: float = Field(default=0.7, ge=0, le=2)
    max_tokens: Optional[int] = Field(default=2048, ge=1, le=128000)
    
    @validator('messages')
    def validate_messages(cls, v):
        for msg in v:
            if not isinstance(msg.get('role'), str):
                raise ValueError("Each message must have a 'role' string")
            if not isinstance(msg.get('content'), str):
                raise ValueError("Each message must have 'content' string")
            if msg['role'] not in ['system', 'user', 'assistant']:
                raise ValueError(f"Invalid role: {msg['role']}")
        return v
    
    @validator('model')
    def validate_model(cls, v):
        allowed_models = ['gpt-4.1', 'claude-sonnet-4.5', 'gemini-2.5-flash', 'deepseek-v3.2']
        if v not in allowed_models:
            raise ValueError(f"Model must be one of: {allowed_models}")
        return v

def create_chat_completion(request: ChatRequest):
    validated = ChatRequest(**request)
    return client.chat.completions.create(**validated.model_dump())
---

6. Output Validation และ Error Handling

from pydantic import BaseModel
from typing import Optional, List

class Message(BaseModel):
    role: str
    content: str

class Usage(BaseModel):
    prompt_tokens: int
    completion_tokens: int
    total_tokens: int

class ChatResponse(BaseModel):
    id: str
    model: str
    choices: List[Message]
    usage: Usage
    created: int

def safe_parse_response(response):
    """Parse response อย่างปลอดภัยพร้อม fallback"""
    
    try:
        if response is None:
            return {"error": "Empty response from API"}
        
        if hasattr(response, 'choices') and len(response.choices) > 0:
            return {
                "content": response.choices[0].message.content,
                "model": response.model,
                "usage": {
                    "prompt_tokens": response.usage.prompt_tokens,
                    "completion_tokens": response.usage.completion_tokens,
                    "total_tokens": response.usage.total_tokens
                }
            }
        
        return {"error": "Unexpected response format", "raw": str(response)}
        
    except Exception as e:
        return {"error": f"Parse error: {str(e)}"}
---

7. Monitoring และ Logging

import time
import logging
from functools import wraps

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def monitor_api_call(func):
    """Decorator สำหรับ monitor latency และ errors"""
    
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        request_id = f"req_{int(time.time() * 1000)}"
        
        logger.info(f"[{request_id}] Starting API call")
        
        try:
            result = func(*args, **kwargs)
            latency = (time.time() - start_time) * 1000
            
            logger.info(f"[{request_id}] Success: {latency:.2f}ms")
            
            # เก็บ metrics
            metrics.append({
                "timestamp": time.time(),
                "latency_ms": latency,
                "success": True,
                "request_id": request_id
            })
            
            return result
            
        except Exception as e:
            latency = (time.time() - start_time) * 1000
            logger.error(f"[{request_id}] Failed: {str(e)} ({latency:.2f}ms)")
            
            metrics.append({
                "timestamp": time.time(),
                "latency_ms": latency,
                "success": False,
                "error": str(e),
                "request_id": request_id
            })
            
            raise
    
    return wrapper

metrics = []

@monitor_api_call
def call_holysheep(messages):
    return client.chat.completions.create(
        model="gpt-4.1",
        messages=messages
    )

ดู metrics

def get_metrics_summary(): if not metrics: return "No metrics yet" successful = [m for m in metrics if m.get('success')] failed = [m for m in metrics if not m.get('success')] latencies = [m['latency_ms'] for m in successful] return { "total_requests": len(metrics), "success_rate": len(successful) / len(metrics) * 100, "avg_latency_ms": sum(latencies) / len(latencies) if latencies else 0, "p95_latency_ms": sorted(latencies)[int(len(latencies) * 0.95)] if latencies else 0 }
---

8. Circuit Breaker Pattern

import time
from enum import Enum

class CircuitState(Enum):
    CLOSED = "closed"      # ปกติ — ทำงานได้
    OPEN = "open"          # ปิด — ปฏิเสธ request ทันที
    HALF_OPEN = "half_open"  # กึ่งเปิด — ลองทดสอบ

class CircuitBreaker:
    def __init__(self, failure_threshold=5, timeout=60):
        self.failure_threshold = failure_threshold
        self.timeout = timeout
        self.failures = 0
        self.state = CircuitState.CLOSED
        self.last_failure_time = None
    
    def call(self, func, *args, **kwargs):
        if self.state == CircuitState.OPEN:
            if time.time() - self.last_failure_time > self.timeout:
                self.state = CircuitState.HALF_OPEN
            else:
                raise Exception("Circuit breaker is OPEN - too many failures")
        
        try:
            result = func(*args, **kwargs)
            self._on_success()
            return result
        except Exception as e:
            self._on_failure()
            raise
    
    def _on_success(self):
        self.failures = 0
        self.state = CircuitState.CLOSED
    
    def _on_failure(self):
        self.failures += 1
        self.last_failure_time = time.time()
        
        if self.failures >= self.failure_threshold:
            self.state = CircuitState.OPEN
            print(f"Circuit breaker OPENED after {self.failures} failures")

ใช้งาน

breaker = CircuitBreaker(failure_threshold=5, timeout=60) def safe_api_call(messages): return breaker.call(client.chat.completions.create, model="gpt-4.1", messages=messages )
---

9. Caching Strategy

import hashlib
import json
import time
from typing import Optional
import redis

class APICache:
    """Cache LLM responses ด้วย Redis สำหรับ identical requests"""
    
    def __init__(self, redis_client, ttl=3600):
        self.cache = redis_client
        self.ttl = ttl
    
    def _make_key(self, messages, model, temperature):
        content = json.dumps({"messages": messages, "model": model, "temperature": temperature})
        return f"llm_cache:{hashlib.sha256(content.encode()).hexdigest()}"
    
    def get_or_fetch(self, messages, model="gpt-4.1", temperature=0.7):
        cache_key = self._make_key(messages, model, temperature)
        
        # ลองดึงจาก cache
        cached = self.cache.get(cache_key)
        if cached:
            print("Cache HIT")
            return json.loads(cached)
        
        print("Cache MISS - calling API")
        response = client.chat.completions.create(
            model=model,
            messages=messages,
            temperature=temperature
        )
        
        # เก็บใน cache
        result = response.choices[0].message.content
        self.cache.setex(cache_key, self.ttl, json.dumps(result))
        
        return result

ใช้งาน

try: cache = APICache(redis.Redis(host='localhost', port=6379), ttl=3600) # Request แรก - เรียก API result1 = cache.get_or_fetch([{"role": "user", "content": "Hello"}]) # Request ที่สองด้วย message เดิม - ใช้ cache result2 = cache.get_or_fetch([{"role": "user", "content": "Hello"}]) except: print("Redis not available, skipping cache")
---

10. Health Check Endpoint

from fastapi import FastAPI, HTTPException
import httpx

app = FastAPI()

HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1"

@app.get("/health")
async def health_check():
    """Health check endpoint สำหรับ load balancer"""
    
    checks = {
        "api_reachable": False,
        "api_responsive": False,
        "latency_ms": None
    }
    
    try:
        # ตรวจสอบว่า HolySheep API accessible
        async with httpx.AsyncClient() as client:
            start = time.time()
            response = await client.get(
                f"{HOLYSHEEP_BASE_URL}/models",
                headers={"Authorization": f"Bearer {os.environ.get('HOLYSHEEP_API_KEY')}"},
                timeout=5.0
            )
            checks["latency_ms"] = (time.time() - start) * 1000
            checks["api_reachable"] = True
            checks["api_responsive"] = response.status_code == 200
            
    except Exception as e:
        checks["error"] = str(e)
    
    # ถ้า latency > 1000ms ถือว่า unhealthy
    if checks["latency_ms"] and checks["latency_ms"] > 1000:
        raise HTTPException(status_code=503, detail="API latency too high")
    
    if not checks["api_responsive"]:
        raise HTTPException(status_code=503, detail="API not responding")
    
    return {"status": "healthy", "checks": checks}

@app.get("/ready")
async def readiness_check():
    """Readiness check — พร้อมรับ traffic หรือยัง"""
    return {"status": "ready"}
---

11-20. Checklist ฉบับย่อ

| # | รายการตรวจสอบ | ความสำคัญ | |---|---------------|-----------| | 11 | SSL/TLS certificate validation เปิดอยู่ | 🔴 บังคับ | | 12 | Request size limit (max_tokens) | 🔴 บังคับ | | 13 | Content filtering/sanitization | 🔴 บังคับ | | 14 | Cost monitoring & budget alert | 🟡 สำคัญ | | 15 | Graceful degradation เมื่อ API down | 🟡 สำคัญ | | 16 | Request/response logging (mask sensitive) | 🟡 สำคัญ | | 17 | Load testing ก่อน deploy | 🟡 สำคัญ | | 18 | Backup API key rotation plan | 🟢 แนะนำ | | 19 | Documentation สำหรับ dev team | 🟢 แนะนำ | | 20 | Runbook สำหรับ incident | 🟢 แนะนำ | ---

ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข

1. 401 Unauthorized — API Key ไม่ถูกต้อง

# ❌ ข้อผิดพลาด

openai.AuthenticationError: Incorrect API key provided

✅ แก้ไข: ตรวจสอบ format และการตั้งค่า environment

import os

1. ตรวจสอบว่า key ถูก set

api_key = os.environ.get("HOLYSHEEP