← Back to Cecep Azhar
Cecep Azhar #golang#websocket#realtime#gorilla-websocket#live-data

WebSocket di Go: Real-time Application Guide

Cecep Saeful Azhar • 16 Oct 2026
WebSocket di Go: Real-time Application Guide
Panduan WebSocket di Go untuk real-time application. Setup Fiber WebSocket, chat, live updates, dan tips performa.

Kenapa WebSocket untuk SaaS?

Real-time experience adalah expectation sekarang. User mau notifikasi instant, live dashboard, dan collaborative editing. WebSocket adalah protocol yang tepat untuk ini full-duplex, low latency, dan efficient.

Saya sudah implement WebSocket di beberapa produk: live chat support, real-time analytics dashboard, dan collaborative project management tool.

Setup WebSocket Server di Go

package handlers

import (
    "log"
    "sync"
    "github.com/gofiber/websocket/v2"
    "github.com/gofiber/fiber/v2"
)

type Client struct {
    Conn *websocket.Conn
    ID   string
    Send chan []byte
}

type Hub struct {
    Clients    map[*Client]bool
    Broadcast  chan []byte
    Register   chan *Client
    Unregister chan *Client
    mu         sync.RWMutex
}

func NewHub() *Hub {
    return &Hub{
        Clients:    make(map[*Client]bool),
        Broadcast:  make(chan []byte, 256),
        Register:   make(chan *Client),
        Unregister: make(chan *Client),
    }
}

func (h *Hub) Run() {
    for {
        select {
        case client := <-h.Register:
            h.mu.Lock()
            h.Clients[client] = true
            h.mu.Unlock()
            log.Printf("Client connected: %s", client.ID)
        case client := <-h.Unregister:
            h.mu.Lock()
            if _, ok := h.Clients[client]; ok {
                delete(h.Clients, client)
                close(client.Send)
            }
            h.mu.Unlock()
        case message := <-h.Broadcast:
            h.mu.RLock()
            for client := range h.Clients {
                select {
                case client.Send <- message:
                default:
                    close(client.Send)
                    delete(h.Clients, client)
                }
            }
            h.mu.RUnlock()
        }
    }
}

Fiber WebSocket Handler

func SetupWebSocketRoutes(app *fiber.App, hub *Hub) {
    app.Use("/ws", func(c *fiber.Ctx) error {
        if websocket.IsWebSocketUpgrade(c) { return c.Next() }
        return c.SendStatus(fiber.StatusUpgradeRequired)
    })

    app.Get("/ws", websocket.New(func(c *websocket.Conn) {
        client := &Client{
            Conn: c, ID: uuid.New().String(),
            Send: make(chan []byte, 256),
        }
        hub.Register <- client

        go func() {
            defer c.Close()
            for message := range client.Send {
                if err := c.WriteMessage(websocket.TextMessage, message); err != nil {
                    return
                }
            }
        }()

        for {
            _, message, err := c.ReadMessage()
            if err != nil { break }
            hub.Broadcast <- message
        }
        hub.Unregister <- client
    }))
}

Real-time Notifications

func (h *Hub) SendToUser(userID string, payload Notification) {
    data, _ := json.Marshal(payload)
    h.mu.RLock()
    defer h.mu.RUnlock()
    for client := range h.Clients {
        if client.UserID == userID {
            select {
            case client.Send <- data:
            default: // Client too slow, skip
            }
        }
    }
}

Performance Tips

WebSocket di Go sangat performant karena goroutine model-nya. Saya pernah handle 50K+ concurrent WebSocket connections di satu server. Untuk scale lebih besar, tambahkan Redis Pub/Sub sebagai message broker antar instances.

Scaling WebSocket dengan Redis Pub/Sub

Ketika SaaS Anda scale ke beberapa server instances, WebSocket messages harus bisa dikirim lintas instances. Redis Pub/Sub adalah solusi yang simple dan efektif:

import "github.com/redis/go-redis/v9"

func (h *Hub) SetupRedisPubSub(rdb *redis.Client) {
    pubsub := rdb.Subscribe(context.Background(), "ws:broadcast")
    ch := pubsub.Channel()

    go func() {
        for msg := range ch {
            var event WSEvent
            json.Unmarshal([]byte(msg.Payload), &event)

            for client := range h.Clients {
                if client.UserID == event.UserID {
                    client.Send <- []byte(event.Data)
                }
            }
        }
    }()
}

Dengan Redis Pub/Sub, semua instances akan menerima message yang sama. Setiap instance hanya mengirim ke local clients yang terhubung. Simple, scalable, dan battle-tested.

Connection Monitoring dan Alerting

Setup monitoring untuk WebSocket connections. Metrics yang perlu di-track:

Gunakan Prometheus metrics exporter untuk collect data ini, lalu visualize di Grafana dashboard. Alert jika connection count atau error rate melampaui threshold tertentu.

← More articles from Cecep Azhar Central Content Hub Home →