auto-sync: 2026-06-09 07:46:02

This commit is contained in:
cfdaily
2026-06-09 07:46:02 +08:00
parent 6e1d86f44a
commit 2b00269d7d
+23 -10
View File
@@ -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: