Bağlantı sürekli kopuyor mu? Sistematik çözüm rehberi
Merhaba!
WebSocket tabanlı gerçek zamanlı uygulamalar (chat, canlı bildirim, multiplayer) geliştirenlerin en sık karşılaştığı sorun: bağlantı kararsızlığı. Bu konuda yaygın nedenleri ve dayanıklı çözümleri derinlemesine ele aldım.
JavaScript:
// ❌ KÖTÜ — bağlantı koparsa hiçbir şey yapmıyor
const soket = new WebSocket('wss://api.example.com/ws');
soket.onclose = () => {
console.log('Bağlantı koptu');
// Hiçbir yeniden bağlanma girişimi yok!
};
// ✅ İYİ — exponential backoff ile akıllı yeniden bağlanma
class GuvenilirWebSocket {
constructor(url) {
this.url = url;
this.yenidenBaglanmaGecikmesi = 1000; // 1 saniyeden başla
this.maksimumGecikme = 30000; // En fazla 30 saniye bekle
this.baglantiKurulumu();
}
baglantiKurulumu() {
this.soket = new WebSocket(this.url);
this.soket.onopen = () => {
console.log('✅ Bağlantı kuruldu');
this.yenidenBaglanmaGecikmesi = 1000; // Başarılı bağlantıda sıfırla
};
this.soket.onclose = (event) => {
console.log(`❌ Bağlantı koptu (kod: ${event.code}), yeniden deneniyor...`);
this.yenidenBaglanmayiPlanla();
};
this.soket.onerror = (hata) => {
console.error('⚠️ WebSocket hatası:', hata);
};
this.soket.onmessage = (mesaj) => {
this.mesajIsle(mesaj.data);
};
}
yenidenBaglanmayiPlanla() {
setTimeout(() => {
this.baglantiKurulumu();
// Exponential backoff — her denemede gecikmeyi ikiye katla
this.yenidenBaglanmaGecikmesi = Math.min(
this.yenidenBaglanmaGecikmesi * 2,
this.maksimumGecikme
);
}, this.yenidenBaglanmaGecikmesi);
}
mesajIsle(veri) {
console.log('📩 Mesaj alındı:', veri);
}
mesajGonder(veri) {
if (this.soket.readyState === WebSocket.OPEN) {
this.soket.send(JSON.stringify(veri));
} else {
console.warn('⚠️ Bağlantı hazır değil, mesaj gönderilemedi');
}
}
}
const guvenilirSoket = new GuvenilirWebSocket('wss://api.example.com/ws');
JavaScript:
// Bazı proxy'ler/load balancer'lar, uzun süre veri akışı olmayan
// bağlantıları "ölü" sayıp otomatik kapatabiliyor — heartbeat bunu önlüyor
class HeartbeatliWebSocket extends GuvenilirWebSocket {
baglantiKurulumu() {
super.baglantiKurulumu();
this.soket.onopen = () => {
console.log('✅ Bağlantı kuruldu');
this.yenidenBaglanmaGecikmesi = 1000;
this.heartbeatBaslat();
};
}
heartbeatBaslat() {
this.heartbeatInterval = setInterval(() => {
if (this.soket.readyState === WebSocket.OPEN) {
this.soket.send(JSON.stringify({ tip: 'ping' }));
}
}, 30000); // Her 30 saniyede bir ping gönder
}
heartbeatDurdur() {
if (this.heartbeatInterval) {
clearInterval(this.heartbeatInterval);
}
}
}
JavaScript:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
// Her bağlantı için canlılık takibi
ws.isAlive = true;
ws.on('pong', () => {
ws.isAlive = true; // Client'tan pong geldi, bağlantı canlı
});
ws.on('message', (mesaj) => {
const veri = JSON.parse(mesaj);
if (veri.tip === 'ping') {
ws.send(JSON.stringify({ tip: 'pong' }));
}
});
ws.on('close', () => {
console.log('Bir client bağlantısı kapandı');
});
});
// ─── SUNUCU TARAFI HEARTBEAT KONTROLÜ ────────────────
// Sunucu, "hayalet" (zombie) bağlantıları periyodik olarak temizler
const heartbeatKontrol = setInterval(() => {
wss.clients.forEach((ws) => {
if (ws.isAlive === false) {
console.log('💀 Yanıt vermeyen client bağlantısı kapatılıyor');
return ws.terminate();
}
ws.isAlive = false;
ws.ping(); // Client'a ping gönder, pong bekleniyor
});
}, 30000);
wss.on('close', () => {
clearInterval(heartbeatKontrol);
});
☐ Exponential backoff ile yeniden bağlanma mantığı var mı?
☐ Heartbeat/ping-pong mekanizması uyguladınız mı?
☐ Bağlantı durumu kontrolü yaparak mesaj göndermeden önce doğruluyor musunuz?
☐ Sunucu tarafında zombie bağlantı temizliği yapılıyor mu?
☐ Yeniden bağlantı sonrası state senkronizasyonu (kaçırılan mesajları alma) düşünüldü mü?
Hangi senaryoda kararlılık sorunu çektiniz, nasıl çözdünüz?