Why I Rewrote the Matching Layer with WebSockets
The initial version of ServiceBridge relied on HTTP short-polling for match notifications. Under load, this caused database connection pool exhaustion and 5+ second notification latency. Here is why I rewrote the matching layer with WebSockets.
The Problem: Stateless Polling at Scale
In a multi-sided marketplace, timing is everything. When a homeowner posts a job, the platform must notify nearby tradespeople immediately. The MVP used HTTP polling: clients pinged the server every 5 seconds asking, "Any new jobs?"
This worked fine at low scale. As concurrent active users grew, the architecture buckled. Every poll required an authentication check, a database query, and a JSON response.
- Database Exhaustion: Thousands of queries per minute to return
[](no new matches). - Latency: A match could take up to 5 seconds to surface on the client, creating a race condition where users felt the app was unresponsive.
- Wasted Bandwidth: High HTTP header overhead for empty payloads.
The Decision: Persistent Stateful Connections
I migrated from stateless HTTP polling to persistent stateful connections using WebSockets via Socket.io.
// WebSocket event architecture
export const setupMatchingGateway = (io: Server) => {
io.on('connection', (socket) => {
// Authenticate and join location-based room
socket.join(`zone_${socket.user.serviceArea}`);
socket.on('job_accepted', async (data) => {
await handleJobAcceptance(socket.user.id, data.jobId);
});
});
}Instead of clients asking the server if anything happened, the server pushes the event to the client the millisecond a match occurs. Result: sub-100ms dispatch notifications.
The Tradeoffs
The performance gains were immediate. But this came at the cost of infrastructure complexity: sticky sessions at the load balancer, mobile reconnection logic for users driving through dead zones, and a Redis Pub/Sub adapter so an event on Node A would reach a user connected to Node B.
Hindsight: I would have evaluated Server-Sent Events before committing to full bidirectional WebSockets. In the ServiceBridge architecture, client-to-server traffic was low relative to server-to-client push volume. SSE over HTTP/2 might have delivered the same latency benefits without the sticky-session complexity.