auto-sync: 2026-06-09 07:46:02
This commit is contained in:
+23
-10
@@ -46,17 +46,37 @@ _TTL_SECONDS = 7 * 24 * 3600
|
||||
_idempotency_lock = asyncio.Lock()
|
||||
|
||||
|
||||
def _is_duplicate(event: str, delivery: str) -> bool:
|
||||
"""检查 Webhook 是否重复投递,自动清理过期条目。"""
|
||||
def _is_duplicate(event: str, delivery: str, payload: Optional[Dict[str, Any]] = None) -> bool:
|
||||
"""检查 Webhook 是否重复投递,自动清理过期条目。
|
||||
|
||||
双重去重策略:
|
||||
1. delivery UUID 去重(标准幂等)
|
||||
2. payload 内容去重(应对 Gitea v1.23.4 的 webhookNotifier + actionsNotifier
|
||||
对同一 review 生成不同 UUID 的双投递问题)
|
||||
"""
|
||||
now = time.time()
|
||||
# 清理过期条目
|
||||
while _delivery_timestamps and (now - _delivery_timestamps[0][0]) > _TTL_SECONDS:
|
||||
_, key = _delivery_timestamps.pop(0)
|
||||
_delivery_cache.discard(key)
|
||||
|
||||
# 检查 delivery UUID 去重
|
||||
key = f"{event}-{delivery}"
|
||||
if key in _delivery_cache:
|
||||
return True
|
||||
|
||||
# 检查 payload 内容去重(review 事件:同一 PR + 同一用户 + 同一内容)
|
||||
if payload and "review" in event:
|
||||
pr_num = payload.get("pull_request", {}).get("number")
|
||||
sender = payload.get("sender", {}).get("login")
|
||||
content = payload.get("review", {}).get("content", "")
|
||||
content_key = f"content:{event}:{pr_num}:{sender}:{content}"
|
||||
if content_key in _delivery_cache:
|
||||
logger.info("Content-based duplicate detected: %s PR#%s by %s", event, pr_num, sender)
|
||||
return True
|
||||
_delivery_cache.add(content_key)
|
||||
_delivery_timestamps.append((now, content_key))
|
||||
|
||||
_delivery_cache.add(key)
|
||||
_delivery_timestamps.append((now, key))
|
||||
return False
|
||||
@@ -462,14 +482,7 @@ async def gitea_webhook(
|
||||
logger.warning("Webhook signature verification failed")
|
||||
return Response(status_code=403, content="signature verification failed")
|
||||
|
||||
# 2. 幂等检查
|
||||
if x_gitea_event and x_gitea_delivery:
|
||||
async with _idempotency_lock:
|
||||
if _is_duplicate(x_gitea_event, x_gitea_delivery):
|
||||
logger.debug("Duplicate webhook: %s/%s", x_gitea_event, x_gitea_delivery)
|
||||
return Response(status_code=200, content="duplicate")
|
||||
|
||||
# 3. 解析 payload
|
||||
# 3. 解析 payload(提前解析,用于幂等检查)
|
||||
try:
|
||||
payload = await request.json()
|
||||
except Exception:
|
||||
|
||||
Reference in New Issue
Block a user