A production-grade, distributed notification infrastructure built in Go. Notify is designed to handle high-throughput event ingestion, guarantee at-least-once delivery, and seamlessly route messages to connected clients in real-time.
Notify operates on a fully decoupled microservices architecture. It separates the write path (ingestion) from the async processing and read paths (delivery), ensuring that spikes in traffic do not degrade the real-time WebSocket experience. The system relies on Kafka as a durable backbone and Redis as an ephemeral state manager and message bus.
The system is composed of three primary Go services:
- API Gateway: A stateless ingestion edge that validates incoming payloads, generates unique idempotency keys, and acts as a Kafka Producer. It also serves historical reads from the database.
- Dispatcher Worker: A Kafka Consumer Group that processes events, enforces idempotency, persists records, and bridges the gap to the real-time layer.
- WebSocket Gateway: A stateless edge that maintains active client connections, subscribes to Redis Pub/Sub, and fans out real-time alerts.
- Durable Event Ingestion: Utilizes Kafka for asynchronous, at-least-once message delivery, ensuring zero data loss during worker outages.
- Two-Tier Idempotency: Protects the database from Kafka retry duplicates using a high-speed Redis
SETNXcache-aside filter, backed by PostgreSQLON CONFLICTunique constraints. - Real-Time Fanout: Leverages Redis Pub/Sub to instantly route Kafka events across any number of horizontally scaled WebSocket gateway instances.
- Offline Persistence: Materializes the notification state in a Neon PostgreSQL database, allowing clients to query their missed history upon reconnection.
- Stateless Edges: Both the HTTP API and WebSocket servers maintain zero local state, allowing them to be scaled out infinitely behind a load balancer.
Ensure you have Docker running for your local Kafka and Redis clusters, and a valid Neon PostgreSQL connection string.
- Clone & Configure: Copy
.env.exampleto.envand supply your database URLs. - Database Setup: Run migrations using the included Makefile.
make migrate-up - Start the Cluster: Spin up the microservices in separate terminal windows:
make run-apimake run-wsmake run-dispatcher
