Add role-based filtering and imporve code
This commit is contained in:
@@ -14,6 +14,7 @@ from urllib.parse import urljoin
|
||||
|
||||
from shared.auth.jwt_handler import JWTHandler
|
||||
from shared.config.base import BaseServiceSettings
|
||||
from shared.clients.circuit_breaker import CircuitBreaker, CircuitBreakerOpenException
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
@@ -91,11 +92,19 @@ class BaseServiceClient(ABC):
|
||||
self.config = config
|
||||
self.gateway_url = config.GATEWAY_URL
|
||||
self.authenticator = ServiceAuthenticator(service_name, config)
|
||||
|
||||
|
||||
# HTTP client configuration
|
||||
self.timeout = config.HTTP_TIMEOUT
|
||||
self.retries = config.HTTP_RETRIES
|
||||
self.retry_delay = config.HTTP_RETRY_DELAY
|
||||
|
||||
# Circuit breaker for fault tolerance
|
||||
self.circuit_breaker = CircuitBreaker(
|
||||
service_name=f"{service_name}-client",
|
||||
failure_threshold=5,
|
||||
timeout=60,
|
||||
success_threshold=2
|
||||
)
|
||||
|
||||
@abstractmethod
|
||||
def get_service_base_path(self) -> str:
|
||||
@@ -113,8 +122,8 @@ class BaseServiceClient(ABC):
|
||||
timeout: Optional[Union[int, httpx.Timeout]] = None
|
||||
) -> Optional[Union[Dict[str, Any], List[Dict[str, Any]]]]:
|
||||
"""
|
||||
Make an authenticated request to another service via gateway
|
||||
|
||||
Make an authenticated request to another service via gateway with circuit breaker protection.
|
||||
|
||||
Args:
|
||||
method: HTTP method (GET, POST, PUT, DELETE)
|
||||
endpoint: API endpoint (will be prefixed with service base path)
|
||||
@@ -123,10 +132,53 @@ class BaseServiceClient(ABC):
|
||||
params: Query parameters
|
||||
headers: Additional headers
|
||||
timeout: Request timeout override
|
||||
|
||||
|
||||
Returns:
|
||||
Response data or None if request failed
|
||||
"""
|
||||
try:
|
||||
# Wrap request in circuit breaker
|
||||
return await self.circuit_breaker.call(
|
||||
self._do_request,
|
||||
method,
|
||||
endpoint,
|
||||
tenant_id,
|
||||
data,
|
||||
params,
|
||||
headers,
|
||||
timeout
|
||||
)
|
||||
except CircuitBreakerOpenException as e:
|
||||
logger.error(
|
||||
"Circuit breaker open - request rejected",
|
||||
service=self.service_name,
|
||||
endpoint=endpoint,
|
||||
error=str(e)
|
||||
)
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Unexpected error in request",
|
||||
service=self.service_name,
|
||||
endpoint=endpoint,
|
||||
error=str(e)
|
||||
)
|
||||
return None
|
||||
|
||||
async def _do_request(
|
||||
self,
|
||||
method: str,
|
||||
endpoint: str,
|
||||
tenant_id: Optional[str] = None,
|
||||
data: Optional[Dict[str, Any]] = None,
|
||||
params: Optional[Dict[str, Any]] = None,
|
||||
headers: Optional[Dict[str, str]] = None,
|
||||
timeout: Optional[Union[int, httpx.Timeout]] = None
|
||||
) -> Optional[Union[Dict[str, Any], List[Dict[str, Any]]]]:
|
||||
"""
|
||||
Internal method to execute HTTP request with retries.
|
||||
Called by _make_request through circuit breaker.
|
||||
"""
|
||||
try:
|
||||
# Get service token
|
||||
token = await self.authenticator.get_service_token()
|
||||
@@ -135,7 +187,11 @@ class BaseServiceClient(ABC):
|
||||
request_headers = self.authenticator.get_request_headers(tenant_id)
|
||||
request_headers["Authorization"] = f"Bearer {token}"
|
||||
request_headers["Content-Type"] = "application/json"
|
||||
|
||||
|
||||
# Propagate request ID for distributed tracing if provided
|
||||
if headers and "X-Request-ID" in headers:
|
||||
request_headers["X-Request-ID"] = headers["X-Request-ID"]
|
||||
|
||||
if headers:
|
||||
request_headers.update(headers)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user