feat(webhook): dedup deliveries by delivery_id (M-7)
This commit is contained in:
52
src/webhooks/_dedup.py
Normal file
52
src/webhooks/_dedup.py
Normal file
@@ -0,0 +1,52 @@
|
||||
"""ORCH-5 (M-7): webhook delivery de-duplication helper.
|
||||
|
||||
Webhook providers (Gitea/Plane) retry deliveries on timeout, network reset, or
|
||||
manual replay. Without idempotency a retried delivery re-enters the pipeline and
|
||||
spawns a duplicate run (the ET-009 incident class: parallel conveyors on one
|
||||
repo). This module computes a stable per-delivery id so the webhook handlers can
|
||||
INSERT-OR-IGNORE into events and skip the dispatch on a repeat.
|
||||
|
||||
delivery_id format: ``f"{source}:{raw_or_hash}"`` where source prefixes
|
||||
gitea/plane so their id-spaces never collide. ``raw`` is the provider's native
|
||||
delivery header (a GUID) when present; otherwise we fall back to a sha256 of the
|
||||
body (a retried identical body yields the same hash).
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
|
||||
|
||||
def _sha256_hex(*parts: str) -> str:
|
||||
h = hashlib.sha256()
|
||||
for p in parts:
|
||||
h.update(p.encode("utf-8", "replace"))
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def gitea_delivery_id(headers, event_type: str, body: bytes) -> str:
|
||||
"""Compute the delivery_id for a Gitea webhook.
|
||||
|
||||
Prefers the ``X-Gitea-Delivery`` header (a per-delivery GUID). Falls back to
|
||||
sha256(source + event_type + body) so a retried identical body still maps to
|
||||
one id even if Gitea omitted the header.
|
||||
"""
|
||||
raw = (headers.get("X-Gitea-Delivery") or "").strip()
|
||||
if not raw:
|
||||
raw = _sha256_hex("gitea", event_type or "", body.decode("utf-8", "replace"))
|
||||
return f"gitea:{raw}"
|
||||
|
||||
|
||||
def plane_delivery_id(headers, body: bytes) -> str:
|
||||
"""Compute the delivery_id for a Plane webhook.
|
||||
|
||||
Plane does not reliably send a delivery header, so we try a couple of common
|
||||
names and otherwise fall back to sha256("plane" + body): a retried identical
|
||||
body yields the same id.
|
||||
"""
|
||||
raw = (
|
||||
headers.get("X-Plane-Delivery")
|
||||
or headers.get("X-Hook-Delivery")
|
||||
or ""
|
||||
).strip()
|
||||
if not raw:
|
||||
raw = _sha256_hex("plane", body.decode("utf-8", "replace"))
|
||||
return f"plane:{raw}"
|
||||
Reference in New Issue
Block a user