{"id":31793537,"url":"https://github.com/easc01/websocket-app","last_synced_at":"2026-04-19T02:08:57.641Z","repository":{"id":316437917,"uuid":"1062559692","full_name":"easc01/websocket-app","owner":"easc01","description":"Non-sticky horizontally scalable websocket application, built by Go and Redis","archived":false,"fork":false,"pushed_at":"2025-09-24T14:47:08.000Z","size":156,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-10T18:19:59.704Z","etag":null,"topics":["go","pubsub","redis","websocket"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/easc01.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-23T12:20:50.000Z","updated_at":"2025-09-28T18:01:57.000Z","dependencies_parsed_at":"2025-09-24T16:38:59.514Z","dependency_job_id":null,"html_url":"https://github.com/easc01/websocket-app","commit_stats":null,"previous_names":["easc01/websocket-app"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/easc01/websocket-app","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easc01%2Fwebsocket-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easc01%2Fwebsocket-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easc01%2Fwebsocket-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easc01%2Fwebsocket-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/easc01","download_url":"https://codeload.github.com/easc01/websocket-app/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easc01%2Fwebsocket-app/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31991721,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"online","status_checked_at":"2026-04-19T02:00:07.110Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","pubsub","redis","websocket"],"created_at":"2025-10-10T18:19:35.908Z","updated_at":"2026-04-19T02:08:57.617Z","avatar_url":"https://github.com/easc01.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# websocket-app\n\n\n`websocket-app` is a high-performance, horizontally scalable WebSocket server framework built in Go, designed to handle real-time messaging at large scale. It is intended for applications such as chat platforms, live dashboards, multiplayer games, and any system requiring real-time communication.\n\nThe architecture emphasizes **non-sticky connections**, enabling users to connect to any server instance without requiring session affinity, while **Redis pub/sub** ensures message fan-out across multiple servers. This approach allows the system to scale horizontally seamlessly, as additional server instances can be added to handle increased client load.\n\nThe project is fully instrumented with **CloudWatch metrics**, allowing monitoring of message throughput, connection counts, latency, and unexpected disconnects, providing visibility into system performance under heavy load.\n\n\n## Architecture\n\n![architecture](/docs/assets/image.png)\n\nThe architecture of `websocket-app` is designed around **high availability, horizontal scaling, and minimal latency**:\n\n1. **Client Layer**: Web clients connect via WebSocket, sending and receiving messages in real-time. Each client is assigned a unique connection ID.\n    \n2. **WebSocket Servers**: Multiple EC2 instances run the Go-based server. Servers maintain a **local map of active clients**, keyed by user ID and connection ID, and handle WebSocket upgrade, message parsing, and client heartbeats.\n    \n3. **Redis Cluster**: Redis acts as the coordination layer. It stores:\n    \n    * `user_servers:\u003cuserID\u003e`: The set of servers a user is connected to, acts as a route table here.\n        \n    * `server:\u003cserverID\u003e`: Pub/sub channel for fan-out messages to users connected to that server\n        \n4. **Message Flow**:\n    \n    * Incoming messages are handled by the local server.\n        \n    * For broadcast or messages to users on other servers, the message is published to Redis channels.\n        \n    * Each server subscribes to its own Redis channel and delivers messages to connected clients.\n        \n5. **Metrics Layer**: Metrics such as total messages, delivered messages, unexpected disconnects, active connections, and average latency are tracked and pushed to **AWS CloudWatch** every 60 seconds.\n    \n\n```\nClients → WebSocket Servers → Redis Cluster (pub/sub) → Other WS Servers → Receiver Clients\n```\n\n\n## Installation \u0026 Setup\n\n### Prerequisites\n\n* [Go 1.24.2](https://go.dev/)\n    \n* [Redis](https://redis.io/) (Cluster enabled)\n    \n* AWS Access Id and Secret Key in environment (aws cli configure recommended)\n    \n* Environment variables for configuration\n    \n\n### Environment Variables\n\nCreate a `.env.local` file with the following variables mentioned in [.env.example](./.env.example).\n\n\n\n### Running Locally\n\n```bash\ngo mod tidy\ngo run cmd/main.go\n```\n\n## Client Lifecycle\n\n1. **Connection**: When a client connects, it is upgraded to a WebSocket, assigned a unique ID, and registered both in the local server and Redis.\n    \n2. **Heartbeat**: Each client sends a heartbeat every 30 seconds to keep connection alive.\n    \n3. **Message Handling**:\n    \n    * Chat messages are published to Redis channels corresponding to the servers where the receiver is connected.\n        \n    * Latency reports update CloudWatch metrics. (Optional, just for metrics)\n        \n4. **Disconnection**: When a client disconnects, all associated keys and mappings are removed, and metrics are updated.\n    \n\n\n## Redis Key Structure\n\n| Key Pattern | Purpose |\n| --- | --- |\n| `user_servers:\u003cuserID\u003e` | Tracks which servers a user is connected to |\n| `server:\u003cserverID\u003e` | Pub/sub channel for message fan-out |\n\n\n## Metrics\n\nThe system pushes the following metrics to AWS CloudWatch:\n\n* **MessagesTotal**: Total messages processed per server\n* **MessagesDelivered**: Successfully delivered messages\n* **ActiveConnections**: Number of live client connections\n* **AverageLatencyMs**: Average message delivery latency\n    \n\nMetrics are published every **60 seconds** and can be visualized on CloudWatch dashboards.\n\n\n## Scaling \u0026 Performance\n\n* **Horizontal Scaling**: Non-sticky connections allow any user to connect to any server instance. Additional EC2 instances can be added linearly to support more concurrent clients.\n    \n* **Redis Cluster**: A high-throughput Redis cluster ensures fast pub/sub operations for message fan-out.\n    \n* **Resource Usage**:\n    \n    * For **10k clients**, 4 × c6i.large instances and a Xlarge Redis cluster are sufficient.\n        \n    * For **30k clients**, consider scaling linearly (e.g., 8 × c6i.large) while monitoring metrics.\n        \n* **Optimization Notes**:\n    \n    * Messages are only sent to servers where the user is connected.\n        \n    * Let Load Balancer terminate the connection, and on termination, remove stale redis keys.\n        \n    * Pub/sub avoids server-to-server direct message passing, reducing inter-server network load.\n        \n\n\n## Running Stress Tests\n\n* Use automated WebSocket clients to simulate load.\n    \n* Monitor CloudWatch metrics for latency, message throughput.\n    \n* Adjust instance counts or Redis cluster size if metrics exceed thresholds.\n  \n* Use the client side code at this [repo](https://github.com/easc01/ws-load-test) to simulate automated ws clients.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasc01%2Fwebsocket-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feasc01%2Fwebsocket-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasc01%2Fwebsocket-app/lists"}