Go Webhook Receiver Starter

Ein kleiner Go-Service, der Webhooks sicher entgegennimmt: signaturgeprüft, dedupliziert, dauerhaft gespeichert und mit Retries. Ihr Code steht in einer einzigen Funktion.

Bei Polar kaufen: $24 Einmalkauf · v0.2.1 · Sofort-Download über Polar

Cover von Go Webhook Receiver Starter
Ausgabe eines echten Testlaufs, kein Mock-up.

Das bekommen Sie

Ein vollständiger Service, den Sie an einem Nachmittag durchlesen können, kein Framework. Ihre Logik gehört in eine Funktion, handle(). Alles drumherum ist fertig und getestet.

sender --POST--> /webhook/{source}
                   1. read the body (size limit)
                   2. verify the HMAC signature   -> 401 if wrong, nothing stored
                   3. dedupe by delivery id       -> the same event twice is handled once
                   4. insert into SQLite          -> 202 Accepted, fast
worker ----------> handle(event)   retries with backoff, dead after N attempts

Funktionen

  • Drei Signaturverfahren. GitHub-Stil, Stripe-Stil (mit Replay-Fenster) und Standard Webhooks, das Verfahren von Polar. Der Vergleich läuft in konstanter Zeit.
  • Secret-Rotation. WEBHOOK_SECRET nimmt eine kommagetrennte Liste. Während einer Rotation gelten altes und neues Secret, und kein Event geht verloren.
  • Deduplizierung. Über die Delivery-ID (bei Standard Webhooks wird automatisch der Header webhook-id verwendet) oder, falls es keine gibt, über einen Hash des Bodys. Eine Unique-Constraint sichert das ab, die Deduplizierung übersteht also Neustarts.
  • Dauerhafte Queue. SQLite im WAL-Modus. Die Anfrage wird nach einem einzigen Commit bestätigt. Dazu kommen exponentielles Backoff, eine Dead-Letter-Ablage nach MAX_ATTEMPTS und die Wiederaufnahme von Events, die ein Absturz im Status processing zurückgelassen hat.
  • Parallelität. WORKERS=N Worker. Ein Event geht nie an zwei Worker zugleich.
  • Betrieb. server replay für Events im Dead-Letter-Status, server purge und RETENTION_DAYS für alte Zeilen, /metrics im Prometheus-Format und ein JSON-Access-Log mit Request-IDs, das weder Payloads noch Header oder Secrets enthält.
  • Sichere Handler. worker.Permanent(err) legt eine Payload ab, die nie erfolgreich sein kann, ohne Retries zu verbrennen. Ein Shutdown mitten im Handler stellt das Event zurück in die Queue, ohne dass ein Versuch verloren geht.
  • Beispiele. Ein Handler für order.paid von Polar und ein generischer JSON-Router, beide mit Tests. Dockerfile und systemd-Unit liegen bei.

Pures Go (ohne cgo). Abhängigkeiten: die Standardbibliothek und modernc.org/sqlite.

Gemessen

Methode: der mitgelieferte Lasttester (make loadtest) gegen das kompilierte Binary auf einem Apple-Silicon-Laptop, 32 Verbindungen, Payloads mit 512 Byte, echtes HTTP über Loopback, Standard-Durability (WAL, synchronous=FULL), 5,000 Events pro Lauf, drei Läufe.

MessungErgebnis
Per HTTP angenommene Events (Signatur prüfen, dauerhaft speichern, 202), GitHub-Stiletwa 7,200 bis 9,200 pro Sekunde (p50 2.7 ms, p99 etwa 17 ms)
Dasselbe mit Standard Webhooksetwa 9,400 pro Sekunde
Ende zu Ende, vom ersten Request bis zur leeren Queue (Handler ohne Arbeit), 1 Workeretwa 3,100 bis 3,200 pro Sekunde
Queue leeren, Handler mit 5 ms Wartezeit (wie ein Netzwerkaufruf), 1 / 8 / 32 Workeretwa 163 / 1,463 / 5,264 pro Sekunde

Den Hauptteil der Kosten verursacht die Datenbank, nicht HTTP. Der gesamte SQLite-Zugriff läuft über eine einzige Verbindung. Mehr Worker lohnen sich daher, wenn Ihr Handler auf etwas wartet, etwa auf einen Netzwerkaufruf oder eine andere Datenbank.

So wurde getestet

make test führt go vet und 41 Tests mit dem Race Detector aus. Sie decken ab: manipulierte, abgelaufene, aus der Zukunft stammende und fehlerhaft aufgebaute Signaturen, den Known-Answer-Vektor von Standard Webhooks aus der Referenzbibliothek in Go, Secret-Rotation, 401 ohne Speichern, doppelte Zustellungen, zu große Requests und falsche HTTP-Methoden, Retries und Backoff, Dead-Letter, Wiederaufnahme nach Absturz, Reihenfolge, viele Worker ohne doppelt verarbeitetes Event, Replay, Purge und das Upgrade einer 0.1.0-Datenbank. Das aus dem fertigen Zip gebaute Binary wurde außerdem mit echten signierten HTTP-Requests für alle drei Verfahren geprüft, einschließlich eines Replays derselben Zustellung.

Für wen es ist

Für Entwickler, die Webhooks von Polar, Stripe, GitHub oder ähnlichen Diensten empfangen müssen und die unscheinbaren Teile richtig erledigt haben wollen: Signaturen, Retries, Deduplizierung und eine Queue, die einen Absturz übersteht.

Es ist für einen einzelnen Server gebaut: ein Prozess, ein SQLite-Writer, Events werden standardmäßig der Reihe nach verarbeitet. Die Zustellung ist at-least-once, Ihr Handler sollte daher idempotent sein.

Häufige Fragen

Prüft es Webhooks von Polar?

Ja. Polar verwendet Standard Webhooks, und das wird unterstützt. Als Beispiel liegt ein Handler für Polar-Bestellungen bei.

Kann ich nur den Signaturcode verwenden?

Ja. Er ist separat als kleines Modul unter MIT-Lizenz erhältlich, webhooksig. Siehe die Seite Kostenlose Tools.

Brauche ich CGO oder einen C-Compiler?

Nein. Der SQLite-Treiber ist pures Go.

Welche Go-Version?

Go 1.24 oder neuer.

Wie ist die Lizenz?

Sie dürfen es in Ihren eigenen Projekten einsetzen. Den Quellcode als konkurrierenden Starter weiterzuverkaufen ist nicht erlaubt.

Änderungsprotokoll

  • 0.2.1: SQLite-Treiber auf v1.44.0 aktualisiert (Go 1.24 oder neuer erforderlich).
  • 0.2.0: Standard Webhooks, Secret-Rotation, mehrere Worker, Replay- und Purge-Befehle, /metrics, Access-Log, Polar-Beispiel, Messwerte.
  • 0.1.0: erstes Release.

Weiterlesen

Herunterladen

Bei Polar kaufen: $24

Zahlung, Steuern und Rechnung übernimmt Polar als Merchant of Record. Den Download-Link erhalten Sie nach dem Checkout.