Módulo 7: Production Patterns

Error Handling & Retries

Exponential Backoff

import time
from openai import APIError, RateLimitError

def get_embedding_with_retry(text, max_retries=5):
    """Retry con exponential backoff"""
    for attempt in range(max_retries):
        try:
            response = client.embeddings.create(
                model="text-embedding-3-small",
                input=text
            )
            return response.data[0].embedding
        
        except RateLimitError:
            if attempt < max_retries - 1:
                wait = 2 ** attempt  # 1s, 2s, 4s, 8s, 16s
                print(f"Rate limit. Retry in {wait}s...")
                time.sleep(wait)
            else:
                raise
        
        except APIError as e:
            print(f"API error: {e}")
            if attempt < max_retries - 1:
                time.sleep(1)
            else:
                raise

Circuit Breaker

from datetime import datetime, timedelta

class CircuitBreaker:
    """Circuit breaker pattern"""
    
    def __init__(self, failure_threshold=5, timeout=60):
        self.failure_threshold = failure_threshold
        self.timeout = timeout  # seconds
        self.failures = 0
        self.last_failure = None
        self.state = 'closed'  # closed, open, half-open
    
    def call(self, func, *args, **kwargs):
        """Execute function con circuit breaker"""
        if self.state == 'open':
            # Check si timeout pasó
            if datetime.now() - self.last_failure > timedelta(seconds=self.timeout):
                self.state = 'half-open'
            else:
                raise Exception("Circuit breaker OPEN")
        
        try:
            result = func(*args, **kwargs)
            
            # Success → reset
            self.failures = 0
            self.state = 'closed'
            return result
        
        except Exception as e:
            self.failures += 1
            self.last_failure = datetime.now()
            
            if self.failures >= self.failure_threshold:
                self.state = 'open'
                print(f"Circuit breaker OPENED after {self.failures} failures")
            
            raise

# Uso
breaker = CircuitBreaker(failure_threshold=5, timeout=60)

try:
    embedding = breaker.call(get_embedding, text)
except Exception:
    # Fallback a modelo local
    embedding = local_model.encode(text)

Graceful Degradation

def get_embedding_robust(text):
    """Multi-level fallback"""
    try:
        # Primary: OpenAI
        return get_embedding_openai(text)
    except Exception:
        try:
            # Fallback 1: SBERT local
            return get_embedding_sbert(text)
        except Exception:
            # Fallback 2: Embedding nulo (graceful fail)
            return np.zeros(1536)

Resumen

  • Exponential backoff: Handle rate limits
  • Circuit breaker: Prevent cascade failures
  • Graceful degradation: Multi-level fallbacks
  • Production: Todos mandatory

Módulo 7 - Cápsula 03