58 Implementasi Subscription dengan gorilla/websocket
Di dunia modern aplikasi web interaktif, notifikasi real-time menjadi kebutuhan wajib. Mulai dari chat, kolaborasi dokumen, hingga update harga saham — semuanya membutuhkan kemampuan server untuk “mendorong” data ke klien secara real-time. Salah satu pola populer untuk menyelesaikan ini adalah Subscription, di mana klien berlangganan pada stream data dan server mengirim update baru ke klien secara langsung.
Pada artikel ini, saya akan membahas secara mendalam bagaimana mengimplementasikan mekanisme subscription menggunakan library gorilla/websocket di Go, yang telah menjadi de-facto standard untuk komunikasi WebSocket di ekosistem Go. Kita akan membahas arsitektur, struktur kode, simulasi alur data, beserta contoh kode nyata dan tips produksi.
Apa itu Subscription?
Sederhananya, subscription adalah model komunikasi di mana klien mendaftarkan minatnya ke event/stream tertentu dan akan menerima update dari server ketika terjadi perubahan. Kebalikannya polling berkala, di mana klien harus meminta informasi baru secara rutin, subscription lebih efisien karena hanya push data baru ketika dibutuhkan.
Studi Kasus
Sebagai contoh, anggap kita memiliki aplikasi monitoring device. Setiap device mengirimkan status secara periodik ke server backend, dan pengguna ingin menerima update real-time jika device status berubah (online/offline, error, dsb).
WebSocket dengan gorilla/websocket
di Go
gorilla/websocket
menyediakan API sederhana untuk upgrade koneksi HTTP konvensional menjadi WebSocket yang full-duplex, dan cocok untuk use case subscription berbasis event seperti ini.
Secara umum, implementasi subscription real-time memerlukan:
- Proses upgrade koneksi HTTP→WebSocket.
- Registry subscription: mapping antara subscriber (klien) dan event/topic yang mereka minati.
- Mekanisme publish: mengirim event/update baru ke subscriber yang relevan.
- Manajemen koneksi — misal deteksi disconnect, retry, dsb.
Mari kita bedah satu per satu.
Diagram Arsitektur
flowchart LR subgraph Server U["HTTP/WS Upgrade"] --> R["Registry Subscription"] R -->|Device Event| P["Publish Event"] P -.->|Push| WSClient1((Client 1)) P -.->|Push| WSClient2((Client 2)) end Device["Updating Device Status"] --> Server
Penjelasan:
- Device melakukan push status ke backend.
- Server menerima dan memproses, lalu meneruskan update ke klien yang telah subscribe melalui WebSocket.
Implementasi Dasar Subscription
Mari kita mulai dengan gigitan kecil: bagaimana menyiapkan server Go yang menerima koneksi WebSocket.
Inisialisasi Handler
// main.go
package main
import (
"log"
"net/http"
"github.com/gorilla/websocket"
)
// WebSocket upgrader dengan konfigurasi standar
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool { return true },
}
func main() {
http.HandleFunc("/ws", handleWebSocket)
log.Println("Listening on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
Handler WebSocket
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("Upgrade error:", err)
return
}
defer conn.Close()
// Sini akan register client, baca subscription dll.
for {
_, msg, err := conn.ReadMessage()
if err != nil {
log.Println("Read error:", err)
break
}
log.Printf("Received: %s", msg)
// Proses message subscription
}
}
Registry Subscription
Umumnya, kita perlu struktur data yang mengelola siapa subscribe ke event apa. Misal, klien bisa subscribe ke beberapa device:
type Subscription struct {
Conn *websocket.Conn
DeviceIDs map[string]bool // devices yang di-subscribe
}
type Hub struct {
Subscriptions map[*websocket.Conn]*Subscription
Register chan *Subscription
Unregister chan *Subscription
Broadcast chan DeviceEvent
}
Penjelasan:
- Hub adalah pusat dari semua subscription, mengelola pendaftaran/penghapusan, serta broadcast event.
- Subscription garisnya satu klien + info subscription-nya.
Proses Workflow Subscription
Mari kita lihat workflow subscription tahap per tahap.
sequenceDiagram participant Client participant Server participant Device Client->>Server: Requests /ws (Upgrade to WS) Server->>Client: WebSocket Connection Established Client->>Server: { "type": "subscribe", "device_id": "dev123" } Device->>Server: Send status update for dev123 Server->>Client: Push event update (if subscribed)
Implementasi Lengkap Hub
Mari kita lengkapi hub yang bisa mendaftarkan subscription serta men-dispatch event.
type DeviceEvent struct {
DeviceID string `json:"device_id"`
Status string `json:"status"`
}
func NewHub() *Hub {
return &Hub{
Subscriptions: make(map[*websocket.Conn]*Subscription),
Register: make(chan *Subscription),
Unregister: make(chan *Subscription),
Broadcast: make(chan DeviceEvent, 128),
}
}
func (h *Hub) Run() {
for {
select {
case s := <-h.Register:
h.Subscriptions[s.Conn] = s
case s := <-h.Unregister:
delete(h.Subscriptions, s.Conn)
case event := <-h.Broadcast:
for _, s := range h.Subscriptions {
if s.DeviceIDs[event.DeviceID] {
s.Conn.WriteJSON(event)
}
}
}
}
}
Update Handler
Setiap ada klien yang mengirim pesan type: "subscribe"
, kita update subscription klien.
// Di dalam handleWebSocket:
var subscription = &Subscription{
Conn: conn,
DeviceIDs: make(map[string]bool),
}
hub.Register <- subscription
for {
var req struct {
Type string `json:"type"`
DeviceID string `json:"device_id"`
}
err := conn.ReadJSON(&req)
if err != nil {
// handle unregistration...
hub.Unregister <- subscription
break
}
if req.Type == "subscribe" {
subscription.DeviceIDs[req.DeviceID] = true
}
}
Simulasi Push Event dari Device
Di aplikasi nyata, push dari device dilakukan dengan MQTT, HTTP, atau gRPC. Di artikel ini, kita simulasi push event via channel.
func simulateDeviceStatus(hub *Hub) {
deviceIDs := []string{"dev100", "dev200"}
statuses := []string{"online", "offline"}
for {
for _, id := range deviceIDs {
status := statuses[time.Now().UnixNano()%2] // acak status
event := DeviceEvent{
DeviceID: id,
Status: status,
}
hub.Broadcast <- event
time.Sleep(5 * time.Second)
}
}
}
Tabel Analisis
Fitur | Polling HTTP | WebSocket+Subscription |
---|---|---|
Latency | Tinggi (interval) | Rendah (push langsung) |
Bandwidth usage | Boros | Hemat |
Scalability | Lumayan sulit | Lebih mudah (stateful) |
Implementasi client | Mudah | Perlu WS lib |
Resilience | Retry manual | Perlu handle disconnect |
Best-Practices untuk Skala Produksi
- Heartbeat/Ping: Kirim ping secara berkala untuk mendeteksi koneksi mati.
- Backpressure: Jangan
WriteJSON
sembarangan, tangani kelambatan klien (buffered channel). - Security: Batasi origin, gunakan Auth (JWT/OAuth), validasi subscription.
- Unregister: Pastikan setiap klien unregister di server ketika disconnect/koneksi error.
- Horizontal Scaling: Untuk scale-out, gunakan shared queue (misal Redis PubSub) antar instance server.
Penutup
Dengan gorilla/websocket
, membangun servis subscription real-time sangat feasible dan clean. Pola Hub seperti di atas sangat cocok di dunia event-driven dan bisa dikembangkan menjadi infra-realtime skala medium besar (untuk skala besar bisa bahas teknologi tambahan, misal message broker/distributed queue).
Membawa notifikasi push ke aplikasi Go Anda kini sangat achievable — dan subscription bisa jadi kekuatan aplikasi Anda berikutnya.
Repo Implementasi contoh:
https://github.com/gorilla/websocket (official)
https://github.com/your-github/real-time-device-subscription (simulasi artikel¹)
¹ Contoh tidak nyata, silakan implementasikan versi dasar di atas.
Terima kasih telah membaca!
Jika bermanfaat, silakan share atau tinggalkan komentar seputar kesulitan implementasi subscription real-time di projek Go Anda.
80. Monitoring gRPC dengan Jaeger + OpenTelemetry
Artikel Terhangat
79. gRPC Logging Terstruktur dengan Zap
08 Aug 2025
56 Apa Itu Subscription di GraphQL?
08 Aug 2025
78. Men-deploy gRPC Service di Docker
08 Aug 2025
77. gRPC di Kubernetes dengan LoadBalancer
08 Aug 2025

79. gRPC Logging Terstruktur dengan Zap

56 Apa Itu Subscription di GraphQL?

78. Men-deploy gRPC Service di Docker
