📝 Basit Anlatım (Sorun Nedir?)
Kullanıcı Muzibu'da müzik dinlerken, tab'ı arka plana alıyor (başka tab'a geçiyor veya bilgisayarı kilitliyor). Müzik çalmaya devam ediyor ✅ ama 1 saat sonra tab'a döndüğünde oturumu kapanmış oluyor.
BU BİR BUG! Kullanıcı müzik dinlemiş, hiçbir şey yapmamış, sadece başka tab'a geçmiş. Ama sistem "60 dakikadır inaktif" diyerek oturumu silmiş.
Kullanıcı laptop'unda müzik açıp çalışıyor, 1 saat sonra tab'a dönüyor, "başka cihazdan giriş yapıldı" uyarısı alıyor. Tekrar login olmak zorunda kalıyor. Çok kötü bir kullanıcı deneyimi!
🔬 Root Cause (Sorunun Kök Nedeni)
🐛 Ana Neden: getActiveDevices() Metodundaki 60 Dakikalık Auto-Cleanup
public function getActiveDevices(User $user): array
{
// Sadece 60 dakikadan eski session'ları temizle (stale cleanup)
DB::table($this->table)
->where('user_id', $user->id)
->where('last_activity', '<', now()->subMinutes(60))
->delete();
return DB::table($this->table)
->where('user_id', $user->id)
->get();
}
Bu kod ne yapıyor?
last_activityalanı 60 dakikadan eski olan session'ları SİLİYOR- Bu cleanup
getActiveDevices()her çağrıldığında çalışıyor getActiveDevices()logout olayında, device listesi gösterilirken çağrılıyor
💤 İkinci Neden: Browser Sleep Mode (Tab Throttling)
Browser sleep mode nedir?
Chrome, Firefox gibi modern tarayıcılar, arka plandaki tab'larda JavaScript'i yavaşlatır veya durdurur (batarya/performans tasarrufu için).
- • Müzik çalıyor ✅
- • Polling her 5 saniyede çalışıyor ✅
- •
last_activitygüncelleniyor ✅
- • Müzik çalıyor ✅ (Audio API korunur)
- • Polling DURUR ❌ (setInterval throttle)
- •
last_activitygüncellenmiyor ❌
last_activity güncellenmiyor çünkü polling durmuş!
60 dakika sonra session "inaktif" kabul edilip siliniyor.
📡 Üçüncü Faktör: Polling Frequency (5 Saniye)
Polling nedir?
Frontend her 5 saniyede bir backend'e "oturumum hala aktif mi?" diye soruyor.
Bu sırada last_activity güncelleniyor.
const SESSION_POLL_INTERVAL = 5000; // 5 saniye
setInterval(() => {
this.checkSessionValidity(); // → /api/auth/check-session
}, SESSION_POLL_INTERVAL);
setInterval durur/yavaşlar →
Polling çalışmaz → last_activity güncellenmiyor!
📊 Gerçek Olay Analizi (19 Aralık 2025 - User 2)
BBB7CVKcYKSqgUlR0EcB...Login token:
3af71df5399f8abb...
•
last_activity sürekli güncelleniyor ✅• Web sunucu log'ları: Her 5 saniyede
/api/auth/check-session isteği ✅
sessionExists: Checking with login_token ✅Web sunucu:
GET /api/auth/check-session → 200 OK ✅last_activity güncellendi: 20:12:18
• Web sunucu log:
0 istek (20:12:17 → 21:41:35 arası)• Laravel log: Hiç
sessionExists çağrısı yok•
last_activity 20:12:18'de kaldı! (güncellenmiyor)• Ama müzik çalıyor olabilir! ✅ (Audio API korunur)
GET /api/auth/check-session → 200 OKPolling tekrar başladı!
sessionExists() çağrıldı2.
getActiveDevices() çağrıldı (logout uyarısı için)3.
getActiveDevices() içinde cleanup çalıştı:
DB::table('user_active_sessions')
->where('last_activity', '<', now()->subMinutes(60))
->delete();
// Hesaplama:
// now() = 21:41:38
// now() - 60dk = 20:41:38
// last_activity = 20:12:18
// 20:12:18 < 20:41:38 → TRUE ✅
// SESSION SİLİNDİ! ❌
devices_count: 0
sessionExists: Login token not found in DB - LIFO kickedFrontend: "Başka bir cihazdan giriş yapıldı" uyarısı
Kullanıcı logout oldu ❌
📜 Log Kanıtları
📄 Laravel Logs (tenant-2025-12-19.log)
{"user_id":2,"cookie_token":"3af71df5..."}
checkSession: Session not found (LIFO kicked)
getActiveDevices DEBUG {"devices_count":0}
Sadece hatalar log'da görünüyor.
🌐 Web Sunucu Logs (access_ssl_log)
Bugün toplam: 3,747 check-session isteği
✅ Çözüm Önerileri
⏰ Cleanup Süresini Artır (60dk → 4 saat)
En basit ve etkili çözüm. 60 dakika çok kısa, kullanıcılar laptop'larını kilitleyip 1-2 saat çalışabiliyor.
// ❌ ESKİ (60 dakika)
->where('last_activity', '<', now()->subMinutes(60))
// ✅ YENİ (4 saat = 240 dakika)
->where('last_activity', '<', now()->subMinutes(240))
- Çok kolay değişiklik (1 satır)
- Test etmeye gerek yok
- Kullanıcı deneyimi düzelir
- DB'de daha fazla session kalır (disk)
- Ama zaten küçük tablo (sorun değil)
🗑️ Cleanup'ı Ayrı Scheduled Task'e Al
getActiveDevices()
içinde cleanup yapmak kötü bir tasarım. Ayrı bir cron job oluştur.
protected function schedule(Schedule $schedule)
{
// Her gece 03:00'te eski session'ları temizle
$schedule->call(function () {
DB::table('user_active_sessions')
->where('last_activity', '<', now()->subHours(24))
->delete();
})->dailyAt('03:00');
}
- Daha temiz mimari
- 24 saat inaktif session'ları temizler
- Kullanıcıya anında etki etmez
- Daha karmaşık
- Cron job yapılandırması gerekir
- Test etmek lazım
📡 Page Visibility API (Polling'i Sleep'te Çalıştır)
JavaScript'e tab arka plana geçse bile polling'i çalıştırmayı söyle.
document.addEventListener('visibilitychange', function() {
if (document.hidden) {
// Tab arka plana geçti
console.log('Tab arka planda, ama polling devam ediyor!');
// setInterval'i durdurma, çalışmaya devam et
} else {
// Tab ön plana geldi
console.log('Tab ön planda');
}
});
- Session her zaman güncel kalır
- 60 dakikalık limit yeterli olur
- Batarya tüketir (her 5 saniyede istek)
- Browser yine de throttle yapabilir
- Garanti değil
⏱️ Polling Frekansını Azalt (5 saniye → 5 dakika)
Üretim ortamında her 5 saniyede polling çok agresif. 5 dakikaya çıkar.
// ❌ TEST: Her 5 saniye (çok sık)
const SESSION_POLL_INTERVAL = 5000;
// ✅ CANLI: Her 5 dakika (yeterli)
const SESSION_POLL_INTERVAL = 300000;
- Server yükü %98 azalır
- Batarya tüketimi azalır
- Browser throttle daha az etkiler
- Logout 5 dakika geç fark edilir
- Ama zaten sorun yok (Çözüm 1'le)
🎯 Önerilen Çözüm
Çözüm 1 + Çözüm 4 Kombinasyonu
- Kullanıcı 4 saate kadar tab arka planda bırakabilir ✅
- Server yükü %98 azalır (5 saniye → 5 dakika) ✅
- Batarya tüketimi azalır ✅
- False positive logout olmaz ✅