diff --git a/src/__pycache__/logging.cpython-311.pyc b/src/__pycache__/logging.cpython-311.pyc index 0d7eb38..b7fabf9 100644 Binary files a/src/__pycache__/logging.cpython-311.pyc and b/src/__pycache__/logging.cpython-311.pyc differ diff --git a/src/auth/service.py b/src/auth/service.py index 2d06f00..dc13fdd 100644 --- a/src/auth/service.py +++ b/src/auth/service.py @@ -78,3 +78,76 @@ async def get_token(request: Request): CurrentUser = Annotated[UserBase, Depends(get_current_user)] Token = Annotated[str, Depends(get_token)] + + +import httpx +import logging +from typing import Dict, Any + +log = logging.getLogger(__name__) + +AUTH_NOTIFY_ENDPOINT = f"{config.AUTH_SERVICE_API}/admin/notify-limit" + +async def notify_admin_on_rate_limit( + endpoint_name: str, + ip_address: str, + method: str = "POST", + cooldown: int = 900, + timeout: int = 5 +) -> Dict[str, Any]: + """ + Kirim notifikasi ke admin via be-auth service ketika rate limit terlampaui. + + Async version - gunakan di async context. + """ + payload = { + "endpoint_name": endpoint_name, + "ip_address": ip_address, + "method": method, + "cooldown": cooldown, + } + + try: + async with httpx.AsyncClient(timeout=timeout) as client: + response = await client.post(AUTH_NOTIFY_ENDPOINT, json=payload) + response.raise_for_status() + result = response.json() + log.info(f"Notifikasi admin sent | Endpoint: {endpoint_name}") + return result + + except Exception as e: + log.error(f"Error notifying admin: {str(e)}") + return {"status": False, "message": str(e), "data": payload} + + +def notify_admin_on_rate_limit_sync( + endpoint_name: str, + ip_address: str, + method: str = "POST", + cooldown: int = 900, + timeout: int = 5 +) -> Dict[str, Any]: + """ + Kirim notifikasi ke admin via be-auth service. + + Sync version - gunakan di exception handler atau sync context. + RECOMMENDED untuk use case ini. + """ + payload = { + "endpoint_name": endpoint_name, + "ip_address": ip_address, + "method": method, + "cooldown": cooldown, + } + + try: + response = httpx.post(AUTH_NOTIFY_ENDPOINT, json=payload, timeout=timeout) + response.raise_for_status() + result = response.json() + log.info(f"Notifikasi admin sent | Endpoint: {endpoint_name}") + return result + + except Exception as e: + log.error(f"Error notifying admin: {str(e)}") + return {"status": False, "message": str(e), "data": payload} + diff --git a/src/exceptions.py b/src/exceptions.py index 18377cb..efea434 100644 --- a/src/exceptions.py +++ b/src/exceptions.py @@ -7,6 +7,7 @@ from fastapi.responses import JSONResponse from pydantic import BaseModel from src.enums import ResponseStatus +from src.auth.service import notify_admin_on_rate_limit_sync from slowapi import _rate_limit_exceeded_handler from slowapi.errors import RateLimitExceeded @@ -104,6 +105,13 @@ def handle_exception(request: Request, exc: Exception): request.state.error_id = error_id if isinstance(exc, RateLimitExceeded): + # Kirim notifikasi ke admin + notify_admin_on_rate_limit_sync( + endpoint_name=request_info["endpoint"], + ip_address=request_info["remote_addr"], + method=request_info["method"], + ) + logging.warning( f"Rate limit exceeded | Error ID: {error_id}", extra={