refactor: ack panel webhooks immediately and run event handling in bounded background task
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import asyncio
|
||||||
import hashlib
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
import json
|
import json
|
||||||
@@ -29,6 +30,10 @@ EVENT_MAP = {
|
|||||||
|
|
||||||
|
|
||||||
class PanelWebhookService:
|
class PanelWebhookService:
|
||||||
|
# Cap parallel background event handlers so an expiry burst from the panel
|
||||||
|
# cannot exhaust the DB pool or the YooKassa client.
|
||||||
|
_MAX_CONCURRENT_EVENTS = 50
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
bot: Bot,
|
bot: Bot,
|
||||||
@@ -42,6 +47,7 @@ class PanelWebhookService:
|
|||||||
self.i18n = i18n
|
self.i18n = i18n
|
||||||
self.async_session_factory = async_session_factory
|
self.async_session_factory = async_session_factory
|
||||||
self.panel_service = panel_service
|
self.panel_service = panel_service
|
||||||
|
self._event_semaphore = asyncio.Semaphore(self._MAX_CONCURRENT_EVENTS)
|
||||||
if not self.settings.PANEL_WEBHOOK_SECRET:
|
if not self.settings.PANEL_WEBHOOK_SECRET:
|
||||||
logging.error(
|
logging.error(
|
||||||
"PANEL_WEBHOOK_SECRET is not configured. Panel webhooks will be rejected."
|
"PANEL_WEBHOOK_SECRET is not configured. Panel webhooks will be rejected."
|
||||||
@@ -243,9 +249,24 @@ class PanelWebhookService:
|
|||||||
telegram_id if telegram_id is not None else "N/A",
|
telegram_id if telegram_id is not None else "N/A",
|
||||||
)
|
)
|
||||||
|
|
||||||
await self.handle_event(event_name, user_data)
|
# Acknowledge immediately so the panel does not retry while we run
|
||||||
|
# auto-renew charges, DB lookups and SMTP. Heavy work is bounded by a
|
||||||
|
# semaphore to survive expiry bursts.
|
||||||
|
asyncio.create_task(
|
||||||
|
self._run_event_in_background(event_name, user_data),
|
||||||
|
name=f"panel_event_{event_name}",
|
||||||
|
)
|
||||||
return web.Response(status=200, text="ok")
|
return web.Response(status=200, text="ok")
|
||||||
|
|
||||||
|
async def _run_event_in_background(self, event_name: str, user_payload: dict) -> None:
|
||||||
|
async with self._event_semaphore:
|
||||||
|
try:
|
||||||
|
await self.handle_event(event_name, user_payload)
|
||||||
|
except Exception:
|
||||||
|
logging.exception(
|
||||||
|
"Panel webhook background handler failed for event %s", event_name
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def panel_webhook_route(request: web.Request):
|
async def panel_webhook_route(request: web.Request):
|
||||||
service: PanelWebhookService = request.app["panel_webhook_service"]
|
service: PanelWebhookService = request.app["panel_webhook_service"]
|
||||||
|
|||||||
Reference in New Issue
Block a user