Automated Action 2adbcd0535 Complete multi-tenant SaaS platform with external integrations
- Implemented comprehensive multi-tenant data isolation using database-level security
- Built JWT authentication system with role-based access control (Super Admin, Org Admin, User, Viewer)
- Created RESTful API endpoints for user and organization operations
- Added complete audit logging for all data modifications with IP tracking
- Implemented API rate limiting and input validation with security middleware
- Built webhook processing engine with async event handling and retry logic
- Created external API call handlers with circuit breaker pattern and error handling
- Implemented data synchronization between external services and internal data
- Added integration health monitoring and status tracking
- Created three mock external services (User Management, Payment, Communication)
- Implemented idempotency for webhook processing to handle duplicates gracefully
- Added comprehensive security headers and XSS/CSRF protection
- Set up Alembic database migrations with proper SQLite configuration
- Included extensive documentation and API examples

Architecture features:
- Multi-tenant isolation at database level
- Circuit breaker pattern for external API resilience
- Async background task processing
- Complete audit trail with user context
- Role-based permission system
- Webhook signature verification
- Request validation and sanitization
- Health monitoring endpoints

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-27 21:14:30 +00:00

94 lines
2.9 KiB
Python

import time
from enum import Enum
from typing import Callable, Any
from dataclasses import dataclass
import logging
from app.core.config import settings
logger = logging.getLogger(__name__)
class CircuitState(Enum):
CLOSED = "closed"
OPEN = "open"
HALF_OPEN = "half_open"
@dataclass
class CircuitBreakerConfig:
failure_threshold: int = settings.CIRCUIT_BREAKER_FAILURE_THRESHOLD
timeout: int = settings.CIRCUIT_BREAKER_TIMEOUT
expected_exception: type = Exception
class CircuitBreaker:
def __init__(self, config: CircuitBreakerConfig):
self.failure_threshold = config.failure_threshold
self.timeout = config.timeout
self.expected_exception = config.expected_exception
self.failure_count = 0
self.last_failure_time = None
self.state = CircuitState.CLOSED
def call(self, func: Callable, *args, **kwargs) -> Any:
"""Execute function with circuit breaker protection"""
if self.state == CircuitState.OPEN:
if self._should_attempt_reset():
self.state = CircuitState.HALF_OPEN
logger.info("Circuit breaker state changed to HALF_OPEN")
else:
raise Exception("Circuit breaker is OPEN")
try:
result = func(*args, **kwargs)
self._on_success()
return result
except self.expected_exception as e:
self._on_failure()
raise e
def _should_attempt_reset(self) -> bool:
"""Check if enough time has passed to attempt reset"""
return (
self.last_failure_time is not None and
time.time() - self.last_failure_time >= self.timeout
)
def _on_success(self):
"""Handle successful call"""
if self.state == CircuitState.HALF_OPEN:
self.state = CircuitState.CLOSED
logger.info("Circuit breaker state changed to CLOSED")
self.failure_count = 0
def _on_failure(self):
"""Handle failed call"""
self.failure_count += 1
self.last_failure_time = time.time()
if self.failure_count >= self.failure_threshold:
self.state = CircuitState.OPEN
logger.warning(
f"Circuit breaker state changed to OPEN after {self.failure_count} failures"
)
def get_state(self) -> CircuitState:
"""Get current circuit breaker state"""
return self.state
def reset(self):
"""Manually reset circuit breaker"""
self.failure_count = 0
self.last_failure_time = None
self.state = CircuitState.CLOSED
logger.info("Circuit breaker manually reset to CLOSED")
# Global circuit breakers for each service
user_service_circuit_breaker = CircuitBreaker(CircuitBreakerConfig())
payment_service_circuit_breaker = CircuitBreaker(CircuitBreakerConfig())
communication_service_circuit_breaker = CircuitBreaker(CircuitBreakerConfig())