Design scalable backend architecture to process high volume webhooks using Redis queue buffering, idempotent workers, and rate limiting.

CEO of Sharcon LLC
15+ years in marketing and development. Leading a team of 30+ professionals at Sharcon.
High volume webhook processing requires a decoupled, asynchronous queue architecture that immediately acknowledges incoming HTTP POST payloads with a 202 Accepted status in under 50 milliseconds while pushing event jobs into a distributed message broker like Redis or Amazon SQS. Processing webhooks synchronously on incoming webservers causes connection pool exhaustion, memory spikes, and dropped payloads when traffic surges to 100k events per minute. Decoupling ingestion from execution guarantees zero message loss, rate limits downstream database writes, and handles provider retries idempotently.
Building a system capable of handling high volume webhook processing demands a clear separation of concerns between receiving data and processing data. When third-party platforms such as Stripe, Shopify, GitHub, or custom IoT sensors transmit thousands of HTTP POST events per second, treating the receiving HTTP server as an execution engine creates immediate bottlenecks.
+-------------------------------------------------------------------+
| Webhook Producers |
| (Stripe, Shopify, GitHub, IoT Sensors) |
+---------------------------------+---------------------------------+
| HTTP POST
v
+-------------------------------------------------------------------+
| API Gateway Ingestion Layer (Fastify / Go) |
| 1. Verify HMAC Signature |
| 2. Push to Queue & Return HTTP 202 Accepted (<30ms) |
+---------------------------------+---------------------------------+
|
v
+-------------------------------------------------------------------+
| Buffered Message Queue (Redis / BullMQ / SQS) |
+---------------------------------+---------------------------------+
|
+-------------------------+-------------------------+
| |
v v
+-------------------------------+ +-------------------------------+
| Worker Node Pool (Consumer) | | Worker Node Pool (Consumer) |
+---------------+---------------+ +---------------+---------------+
| |
+-----------------+-----------------+
|
v
+-------------------------------------------------------------------+
| Target Database (PostgreSQL Upsert) |
+-------------------------------------------------------------------+
In a traditional synchronous handler, the receiving endpoint performs multiple sequential tasks before returning an HTTP response: parsing the JSON body, validating signatures, querying the database, executing business logic, and updating row states.
Under normal conditions with low traffic, this process takes 150 to 400 milliseconds. However, when an upstream platform sends bursts of 100k events per minute, three catastrophic failures occur:
502 Bad Gateway or 504 Gateway Timeout.To eliminate these vulnerabilities, deploy a lightweight API Gateway built with runtimes such as Fastify (Node.js) or Go that executes only signature verification and queue enqueuing before terminating the connection.
For microservices engineering and API infrastructure, review our backend and API development services.
The message queue serves as a buffer between external webhook senders and internal database infrastructure. Regardless of whether incoming volume spikes to 100k events per minute, the ingestion gateway enqueues messages at constant speed, allowing downstream workers to process events at a controlled rate.
| Feature / Criteria | Redis (BullMQ) | Amazon SQS | Apache Kafka | | --- | --- | --- | --- | | Ingestion Latency | Sub-millisecond (< 2ms) | 10ms – 25ms | Sub-millisecond (< 5ms) | | Throughput Target | Up to 100,000 events/sec | Virtually unlimited | Exceeds 1,000,000 events/sec | | Ordering Guarantees | Strict FIFO per queue | FIFO mode available | Strict per partition key | | Operational Effort | Low to Medium | Zero (Serverless) | High (Requires Cluster Tuning) |
For high volume webhook processing implementations handling up to 100k events per minute, Redis paired with BullMQ offers low latency ingestion, minimal overhead, and rich queue primitives.
Events that fail execution due to schema mismatches or database outages must not block the queue. Configure a Dead Letter Queue policy:
webhook-dlq queue.Webhook providers deliver events with an "at-least-once" guarantee. Due to transient retries or timeouts, your backend receives duplicate events. Without idempotency protections, processing duplicate webhooks leads to duplicate charges and corrupted state.
To enforce idempotency without querying primary databases on every event, workers execute an atomic lock check in Redis using SETNX:
evt_...).SET webhook:idempotency:{event_id} processing NX EX 86400 (setting a 24-hour expiration window).NULL (key exists), terminate processing immediately.OK (key created), proceed with downstream payload parsing.completed.Inserting row by row into PostgreSQL during a 100k events per minute surge generates write amplification and disk I/O bottlenecks. Workers aggregate individual events into memory buffers and execute multi-row bulk updates.
Instead of executing 1,000 single INSERT queries per second, workers accumulate jobs over a short sliding window (e.g., 100 milliseconds) and execute a single batch query:
INSERT INTO webhook_events (event_id, provider, event_type, payload, processed_at)
SELECT * FROM UNNEST(
$1::uuid[], $2::text[], $3::text[], $4::jsonb[], $5::timestamptz[]
)
ON CONFLICT (event_id)
DO UPDATE SET payload = EXCLUDED.payload, processed_at = EXCLUDED.processed_at;
This batching transformation reduces database round-trips by up to 99%, dropping CPU consumption on PostgreSQL instances.
To integrate high-throughput event processing with external applications, explore our integrations & software API services.
The following implementation demonstrates an ingestion gateway written in Fastify paired with a BullMQ queue processor and PostgreSQL client.
gateway.js)import Fastify from 'fastify';
import crypto from 'crypto';
import { Queue } from 'bullmq';
import Redis from 'ioredis';
const fastify = Fastify({ logger: true });
const redisConnection = new Redis(process.env.REDIS_URL || 'redis://localhost:6379');
const webhookQueue = new Queue('incoming-webhooks', { connection: redisConnection });
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET || 'whsec_secret_key_8f92a3';
fastify.addContentTypeParser('application/json', { parseAs: 'buffer' }, (req, body, done) => {
req.rawBody = body;
try { done(null, JSON.parse(body.toString())); } catch (err) { done(err, null); }
});
fastify.post('/api/webhooks/v1/ingest', async (request, reply) => {
const signature = request.headers['x-webhook-signature'];
if (!signature) return reply.status(401).send({ error: 'Missing signature header' });
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
const digest = hmac.update(request.rawBody).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest))) {
return reply.status(403).send({ error: 'Invalid signature' });
}
const eventId = request.body.id || request.headers['x-request-id'];
await webhookQueue.add(
'process-event',
{ eventId, eventType: request.body.type, payload: request.body, receivedAt: new Date().toISOString() },
{ jobId: eventId, attempts: 5, backoff: { type: 'exponential', delay: 2000 }, removeOnComplete: true }
);
return reply.status(202).send({ status: 'accepted', eventId });
});
fastify.listen({ port: 3000, host: '0.0.0.0' });
worker.js)import { Worker } from 'bullmq';
import Redis from 'ioredis';
import pg from 'pg';
const redisClient = new Redis(process.env.REDIS_URL || 'redis://localhost:6379');
const dbPool = new pg.Pool({ connectionString: process.env.DATABASE_URL, max: 20 });
const worker = new Worker(
'incoming-webhooks',
async (job) => {
const { eventId, eventType, payload, receivedAt } = job.data;
const lockKey = `webhook:idempotency:${eventId}`;
const acquired = await redisClient.set(lockKey, 'processing', 'NX', 'EX', 86400);
if (!acquired) return { skipped: true, eventId };
try {
const query = `
INSERT INTO webhook_events (event_id, event_type, payload, received_at, status)
VALUES ($1, $2, $3, $4, 'processed')
ON CONFLICT (event_id) DO NOTHING;
`;
await dbPool.query(query, [eventId, eventType, JSON.stringify(payload), receivedAt]);
await redisClient.set(lockKey, 'completed', 'EX', 86400);
return { success: true, eventId };
} catch (error) {
await redisClient.del(lockKey);
throw error;
}
},
{ connection: redisClient, concurrency: 50 }
);
Engineering teams must decide whether to build a self-hosted architecture or utilize managed platforms.
| Feature / Metric | Self-Hosted (Fastify + BullMQ) | Managed Platform (Hookdeck / Svix) | AWS Native (SQS + EventBridge) | | --- | --- | --- | --- | | Ingestion Control | Custom control over middleware | Pre-built SaaS proxy | Serverless architecture | | Operational Effort | Medium (Managing Redis & K8s) | Zero infrastructure management | Low (Managed services) | | Signature Verification | Custom code per provider | Pre-built for 100+ providers | Requires Lambda Authorizers | | Alerting & UI | Custom Prometheus/Grafana | Built-in UI dashboards | CloudWatch Alarms |
When evaluating managed options versus self-hosted server deployments:
A reliable high volume webhook processing engine requires continuous telemetry to detect bottlenecks before queue saturation occurs:
To build monitoring views and operational displays for your backend events, explore our custom dashboard development services.
Deploy a stateless API Gateway layer using Fastify or Go that performs signature validation and enqueues events directly into Redis or SQS. Return an HTTP 202 Accepted response within 30 milliseconds.
Use HTTP 202 Accepted. This status code signals to the sending platform that the webhook payload has been received and accepted for asynchronous processing.
Retain idempotency keys in Redis for 24 to 72 hours using key expiration (TTL). Most major webhook senders complete retry cycles within 24 hours.
Choose a managed platform like Hookdeck or Svix for turn-key signature verification and event replay dashboards. Choose self-hosted Fastify and BullMQ if you have strict compliance requirements or process high volumes where SaaS pricing is cost-prohibitive.
If your application handles expanding integration demands or experiences performance bottlenecks during peak webhook traffic, Sharcon designs resilient, event-driven backends built for high throughput.
Contact our backend engineering team to architect a scalable API gateway and queue infrastructure tailored to your stack.

CEO of Sharcon LLC
15+ years in marketing and development. Leading a team of 30+ professionals at Sharcon.