From 0df6225624560e5252a1db6cc37cc6c22976c07e Mon Sep 17 00:00:00 2001 From: Cizz22 Date: Thu, 26 Feb 2026 11:45:50 +0700 Subject: [PATCH] feat: Add admin notification functionality for rate limit exceedances and integrate it into the rate limit exception handler. --- src/__pycache__/logging.cpython-311.pyc | Bin 5130 -> 5509 bytes src/auth/service.py | 73 ++++++++++++++++++++++++ src/exceptions.py | 8 +++ 3 files changed, 81 insertions(+) diff --git a/src/__pycache__/logging.cpython-311.pyc b/src/__pycache__/logging.cpython-311.pyc index 0d7eb38dfe4bbb8c6cccd46a109e507c890f316a..b7fabf9bf528d980b31d3edd00ac58bc145dbb36 100644 GIT binary patch delta 1790 zcmah}OKcNI7@oCv*ZcB=IF4~btc2Jh3519UMJO#rh|ok-fI?`i^krGzwPWJ-hS^OZ zXibo+N>Z9(tigYI~^E_Rvc&#Hl4#D^+bz?WM)25B1jmvnCWMQrDhO z^L_LG-~98~eS6@oy`c|+K?%Y0^DozmzqWl8dd?Rg9+@+AZ6s^q?8t<+q?L>XT`ODU zW#5l09EAFz{q_mqRirYiuY`1_;?sQE^y6B%p7Z^*~jz;JlPwxAZ z4d$;Xm7uNI@)CnPZDk`y z1D;odtxfPI1~550XiK(2ecwr0!`nJ+Vtl)AOONMNLgXHo?R|J0YUuGLSHgDq8nQ#= zJRe&L&7i^XDNOfckaa@^&B|cy{Gw)BnWE~-lrNeZrbO8$<*cr`f){F(v`ahEv%_h9 zIIZ@ir^eGK$I~<5Bw9rsOtSid%a!Q8by+Vh0IHcSXl}r>O@psMd)^?6!OxW*DL~LL zHZYL_yGA>qMAxsI1((g@f{A-6=X6ucnJ#DMj0Mf*OU1HQHe6me)WwoUW&)|M-83w) zfQ=kX>;@iq<2@jgcLPbu74nPa+$mTRxfOUd#bjJGm~>?m=l17}vZYF?#^{jRL zVoqDIibfgJLw4nsI%8#X^DbAkG~IM1*hp-d7mC)L%bqihvdfVzVdP-MWlgP=cX_Pk z46OdAP+C(zg+2-?3TYA-k4X{e_IM9@LmXXE;rOp0N0{0CzyA-hL{)OyI;sID8m|gY zI9g?!EHCbG5_{H@^~7K!F<3p}boAEdSM@c$I_bpwYWC{owae8hC)!mzv^u^vUY)2; z{PkUUXA?2v4ghjTjIBthb9W;#bT@HmD{<(vj?ckts*#wwo0#58OmCji>WO?Kk#}NU zjab@g?_7JqiFehYmQe5fgM9a0kkRHbGFDN*Xa&q?jAo~SL?m0m~ol>JV6 z7?ewOWw#@TX-vP+s&d5%h(0RPlc$Ge;G&EO#>*a#ij+H^BK|=IUjW8l2ItY>q}oRvKl$eEyLja?QbJ*GVKK#cbdX+0M}=jc$&<& zP4v7(wX+n0bU=LGyQdbsiU}$%lRItQ(iP~!_Zpe)Hq)$ delta 1380 zcmZWoU1%It6u$GjGqaoBB+c$-k|uQ1gl1Eds_`djno6}XrI<$CRtz>Q!_3Wg(w&*j zoyiY6OB4}95wYA9g+{0dHBeuqFMa5f;G>X)l`Iz(eeq3msYwG=7QXtxey!!pP9K!$z{#rLJfS=B7I9IFg&d5~!Vc z#BMsUKan1ee>j%v|HcJf`xyYtr|@+-lL&*3X7Z4-!97&d7P(*NH5&A*VwjOXNiCmZ| zT%4H7YeWrfhx!etLZmWWf@Kn;wr`XmiI=@n38JEFIFKl1&olztbBXMD)?%4@<`!M^ z0^{Ve?LyZhLdCX-hM*K}g*Rh|2X)#45gflnL<5z4B1Xj|$A_j*B;WKZ5cSa*bd&=A zGuAtLgk{7k$TMjhB=%3=M1d=2(RSy&h8Dn;fOcS)AuEV_S@x{*dMn6xlemw}A=7hN z4C=(+DgCQYu%epbvti%xTu4;g_vSq07y%lMIC@4?jk(cd)DiU)m5tgXyyp{{#?T4T z(<~v?$evg+VTBzFI?258hPMzH=2fB;i{_IN>Usq4o+?%vk(H9fy}e(gN2 zYq?bgboA8pfn9xMM<2PDxlj3XHT~SKUf9tK+xn%NerZ=P?&!sB-KgnCJ>6ML_tmpq zyV?GoZ2xw4pq3q|cjh+67>sYVzeJzSXTEr@q1}7+{%k|5XAZAB_4e+KRHS`>D7`*< zeQZ5DR`2ND>Uexp*-OVW+8&@lyY0r`#HTq0cO}O0)r6U1zu`444Q^;X!lzsh{xQ+T z&EmfjIc^XiY0}eAN$q>!QMg-Z8WQDcc33at_gWStlw+qQwT??mRJnY2vh^J<4H-Yh z;CTj<45sl9ht5u3Wa=vn*xyXl7o(3KK!n&8MXUx&GsrN=Qh1=8YTWeGD5NI+B*0H# eyY1_t5so(afB0~+*4FnMBmOvGmpE*tbAJQa&u+K? 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={