Episode ini membahas menjaga kesehatan koneksi: mekanisme ping-pong, interval heartbeat, deteksi koneksi mati, serta presence pengguna seperti status online, offline, dan terakhir aktif.

Koneksi WebSocket yang tampak sehat bisa saja sudah mati: jaringan putus di tengah jalan, perangkat tidur, atau router dihapus karena tidak ada trafik. Tanpa pengecekan, server tidak akan pernah tahu sampai pengguna mencoba mengirim pesan dan gagal.
Episode 11 membahas heartbeat: mekanisme ping-pong untuk memastikan koneksi hidup, dan presence: pengetahuan server tentang siapa yang online, offline, sibuk, atau sudah lama tidak aktif. Ini fondasi aplikasi seperti chat yang menampilkan status hijau dan titik abu-abu.
Protokol WebSocket punya frame kontrol ping dan pong. Klien atau server mengirim ping, lawan menjawab pong. Jika tidak ada pong, koneksi dianggap mati.
ws.onopen = () => {
heartbeat();
};
function heartbeat() {
clearTimeout(ws.pingTimeout);
ws.pingTimeout = setTimeout(() => {
console.log("tidak ada pong, menutup koneksi");
ws.close();
}, 30000);
}
ws.onpong = () => {
console.log("pong diterima, koneksi sehat");
heartbeat();
};Di browser tidak ada API untuk mengirim ping secara manual, jadi contoh di atas memanfaatkan pong otomatis browser sebagai penanda koneksi hidup. Timer 30 detik dimulai ulang setiap kali pong diterima.
Di sisi server Node.js dengan library ws, ping bisa dikirim langsung.
const wss = new WebSocketServer({ port: 8080 });
function heartbeat() {
clearTimeout(this.isAlive);
this.isAlive = setTimeout(() => this.terminate(), 30000);
}
wss.on("connection", (ws) => {
ws.isAlive = null;
heartbeat.call(ws);
ws.on("pong", () => heartbeat.call(ws));
});
setInterval(() => {
wss.clients.forEach((ws) => {
if (!ws.isAlive) return;
ws.ping();
});
}, 10000);Setiap 10 detik server mengirim ws.ping() ke semua klien. Jika tidak ada pong dalam 30 detik, ws.terminate() memutus koneksi yang dianggap mati. Pola isAlive yang direset oleh pong ini adalah standar di dokumentasi ws.
Presence adalah informasi di atas level koneksi: bukan hanya koneksi hidup, tapi apa yang sedang dilakukan pengguna.
const pengguna = new Map();
io.on("connection", (socket) => {
socket.on("presence:set", (status) => {
pengguna.set(socket.userId, {
status,
terakhirAktif: Date.now(),
});
io.emit("presence:update", {
userId: socket.userId,
status,
});
});
socket.on("disconnect", () => {
pengguna.set(socket.userId, {
status: "offline",
terakhirAktif: Date.now(),
});
});
});Map pengguna menyimpan status per pengguna. Saat koneksi putus, status diubah menjadi offline otomatis. Field terakhirAktif bisa menampilkan teks seperti "aktif 5 menit lalu".
Presence tidak hanya soal koneksi — kalian juga bisa melacak aktivitas klien.
let idleTimer;
socket.on("input:activity", () => {
clearTimeout(idleTimer);
setStatus("online");
idleTimer = setTimeout(() => setStatus("away"), 120000);
});Timer 120 detik di-reset setiap kali pengguna beraktivitas. Jika tidak ada aktivitas, status berubah menjadi away. Kombinasi koneksi hidup dan aktivitas menghasilkan presence yang jauh lebih akurat.
Perubahan presence harus disiarkan agar semua klien menampilkan status terbaru.
function setStatus(status) {
socket.emit("presence:me", { status });
socket.to("room:utama").emit("presence:user", {
userId: socket.userId,
status,
});
}socket.to("room:utama") memastikan hanya anggota room yang menerima pembaruan. Saat masuk aplikasi, klien juga meminta daftar status semua pengguna untuk merender status awal.
Pada satu server, Map sederhana sudah cukup. Saat server bertambah banyak, presence harus disimpan di tempat bersama seperti Redis agar setiap instance melihat status yang sama. Pendekatan ini akan dibahas lebih dalam di episode 16.
Socket.IO sudah menangani ping-pong secara internal dengan dua opsi utama.
const io = new Server(server, {
pingInterval: 25000,
pingTimeout: 20000,
});pingInterval menentukan jarak server mengirim ping, dan pingTimeout batas waktu menunggu pong sebelum koneksi diputus. Total di atas berarti koneksi mati terdeteksi dalam maksimal 45 detik. Nilai ini bisa disesuaikan dengan kondisi jaringan pengguna.
Episode 11 memberi kalian kemampuan mendeteksi koneksi yang sebenarnya sudah mati dan menampilkan presence yang akurat. Heartbeat mencegah kebocoran resource, presence membuat aplikasi terasa hidup dan responsif.
Inti yang harus dibawa pulang:
Di episode 12 berikutnya kita membahas error handling & reconnection strategies: jenis-jenis kegagalan koneksi, exponential backoff, konfigurasi reconnection Socket.IO, serta pemulihan state setelah koneksi kembali.