A Python integration sample connecting provider-specific signature checks, delivery-state storage and asynchronous handler callbacks. It includes in-memory and SQLite stores plus a demonstration FastAPI server.
The repository illustrates local integration mechanisms. It does not establish distributed processing, exactly-once side effects or production reliability.
- HMAC-SHA256 verification adapters for Stripe, GitHub and Shopify; the Stripe adapter also checks its signed timestamp against a configured tolerance.
- A provider-and-body-derived key for checking previous deliveries.
- Handler dispatch with stored processing, delivered, failed and dead-letter states.
retry_failed()explicitly reruns failed events; it does not implement a scheduled exponential-backoff worker.- SQLite storage for local state, or an in-memory store for demonstrations.
- A FastAPI demonstration with an event stream and in-process counters.
git clone https://github.com/builtbyhuy/webhook-gateway.git
cd webhook-gateway
uv sync
uv run pytest tests/ -vimport asyncio
from webhook_gateway.core import WebhookGateway
from webhook_gateway.providers.stripe import StripeProvider
from webhook_gateway.store.sqlite import SQLiteEventStore
async def main():
store = SQLiteEventStore("events.db")
gateway = WebhookGateway(store=store, max_retries=3)
gateway.register_provider(StripeProvider(signing_secret="whsec_test_secret"))
@gateway.on_event
async def process_event(event):
print(event.event_id, event.provider)
# Supply a correctly signed synthetic body to gateway.ingest(...) here.
# No production provider or downstream account is connected by this example.
store.close()
asyncio.run(main())The checked-in tests exercise event state, signature validation, duplicate handling, handler failures, explicit retries, and local stores. Run the suite on the revision being reviewed. Test count and passing status are execution results, not coverage percentages or evidence of a production service.
uv run python benchmarks/bench_ingestion.pyThe script makes 1,000 sequential, in-process calls using synthetic Stripe signatures, a local SQLite store and a no-op handler. It then repeats the bodies sequentially to time the duplicate path. There are no HTTP requests, concurrent load, real provider calls, network partitions or downstream mutations in this benchmark. It does not measure a FastAPI baseline or protection against replay attacks.
- Duplicate lookup and storage are separate operations. The SQLite idempotency index is not unique, so simultaneous workers can both dispatch a delivery.
- A crash after recording
PROCESSINGcan leave an event suppressed without proving whether its downstream effect occurred. There is no lease or receipt reconciliation protocol. - Retrying runs the handler list again. Effects from an earlier successful handler can repeat if a later handler fails.
- A bounded attempt counter does not make downstream effects exactly once.
- The default HTTP server uses memory, registers no providers automatically, and exposes administration routes without authentication. It is a local demonstration and needs access controls, body limits and durable operational state before any public deployment.
- Real-provider compatibility, credential rotation and multi-process recovery require separate verification.
MIT © Hồ Khắc Huy