Omnichannel Engagement
Real-time customer support gateway in Go: WebSocket connections for customers and agents, a least-busy routing engine, Redis-backed presence with TTL and pub/sub fan-out, and an SLA scheduler that escalates conversations an agent has gone quiet on.
Overview
Omnichannel Engagement is a real-time customer support gateway built to prove a different Go skill than my other Go project (a gRPC/NATS microservices logistics platform): concurrency and presence, not service decomposition. Customers and agents both connect over WebSocket to the same Hub, which assigns every new conversation to the least-busy online agent, tracks who's online through Redis (not local memory, so the design is ready for more than one gateway instance), and escalates a conversation automatically if an agent goes quiet past an SLA window.
The Challenge
- The interesting problems here are all about state that outlives a single request.
- A WebSocket connection is pinned to one process, so "is this agent online" cannot be answered from memory once there is more than one instance.
- An assignment decision has to stay correct as conversations move between agents.
- And an SLA breach has to be detected without any customer or agent action, purely by a background process noticing time has passed.
The Solution
- Kept the assignment decision (routing.
- PickLeastBusy) and the conversation state machine as pure Go with no I/O, so both are unit tested with plain structs.
- Presence is a Redis key with a TTL refreshed by a heartbeat, not a boolean: if a gateway instance crashes, its agents fall back to offline automatically instead of staying stuck online, and a pub/sub channel exists for other instances to stay in sync.
- Verified all of it against the real stack with a small Go WebSocket test client rather than trusting the code: brought two real agents online and confirmed the busier one was skipped, watched a live Redis key's TTL count down and disappear on disconnect, and shortened the SLA window to watch a real escalation event arrive over an open WebSocket connection.