Skip to content

Reliable webhook engine implementing Idempotency, Strict Entity Ordering, and Audit Logging to handle distributed events safely.

Notifications You must be signed in to change notification settings

GersonResplandes/webhook-processor

Repository files navigation

Webhook Processor

CI Status

🇧🇷 Leia em Português

Reliable webhook processing service that implements Idempotency, Strict Ordering by Entity, and Audit Logging. Built to demonstrate correctness in handling distributed events.

Portfolio Note: This project prioritizes architectural correctness, clean code, and transparency in trade-offs. It serves as a reference implementation for securely handling asynchronous event processing patterns.


🏗 Logical Flow

flowchart TD
    In([Webhook Request]) --> Validate{Valid Payload?}
    
    Validate -- No --> R400[400 Bad Request]
    Validate -- Yes --> Idem{Idempotency Check}
    
    Idem -- Duplicate & Processed --> R409[409 Conflict]
    Idem -- Duplicate & Failed --> Retry[Retry: Reset & Accept]
    Idem -- New Event --> Accept[202 Accepted]
    
    Retry --> Queue
    Accept --> Queue
    Queue --> Lock{Acquire Mutex}
    Lock --> Process[Sequential Processing]
    
    Process -- Success --> DB_OK[(DB: PROCESSED + Audit)]
    Process -- Error --> DB_FAIL[(DB: FAILED + Audit)]
Loading

🚀 Key Features & Decisions

1. Robust Idempotency

Prevents "double spending" or duplicate side effects when providers send the same event multiple times.

  • Mechanism: Database uniqueness constraint on event_id.
  • Enhancement: Distinguishes between "Already Processed" (Conflict) and "Previous Failure" (Retry Allowed). This prevents the common "zombie state" problem where failed events block new attempts.

2. Entity Ordering (Concurrency Control)

Ensures that OrderCreated is always processed before OrderPaid.

  • Mechanism: In-memory mutex/locking per customer_id.
  • Goal: Allows parallel processing between different customers while maintaining a strict sequence for each customer.
  • Safety: Implements a "Queue Safe Promise" pattern to ensure that a single failure does not cause a permanent deadlock in the client's queue.

3. Complete Auditability

All decisions—whether accepted, ignored, processed, or rejected—are permanently logged.

  • Why? Essential for debugging production issues where providers claim "we sent it" but the system state disagrees.

🛠 Tech Stack

  • Runtime: Node.js 20+ (TypeScript Strict Mode)
  • Framework: Express
  • Database: MySQL 8.0 (via Docker)
  • ORM: Prisma (Schema and Migrations)
  • Testing: Jest + Supertest (Unit and Integration Mocks)
  • Validation: Zod
  • Documentation: Swagger/OpenAPI

⚡ Quick Start

1. Setup Environment

cp .env.example .env

2. Start Infrastructure

docker-compose up -d

3. Install & Migrate

npm install
npm run db:migrate

4. Run Locally

npm run dev
# Swagger Docs at http://localhost:3000/api-docs

⚠️ Known Limitations (Architectural Trade-offs)

This architecture makes explicit trade-offs for simplicity and consistency in a single-node environment.

Constraint Implication Production Solution (Scale)
In-Memory Locks Scaling to multiple instances breaks ordering guarantees. Redis Lock (Redlock) or Kafka Partitioning (keyed messages).
No Dead Letter Queue Failed events remain FAILED in the database. Separate DLQ table + Retry mechanism.
Synchronous DB Writes Higher latency on accepting requests. Decouple ingestion (SQS/RabbitMQ) from storage.

👨‍💻 Author

Gérson Resplandes
Backend Engineer focused on Distributed Systems and Reliability.

LinkedIn Email

About

Reliable webhook engine implementing Idempotency, Strict Entity Ordering, and Audit Logging to handle distributed events safely.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published