Kafayı yiyecektim! Haftalardır sorunsuz çalışan otomasyon botum bir anda "Connection refused" vermeye başladı. Loglara baktım, gözlerime inanamadım: OSError: [Errno 24] Too many open files. Meğerse bot, her işlemde açtığı socket bağlantılarını düzgün kapatmayı unutmuş, sistem limitini patlatmıştı.
Hatayı Bulma Maceram
İlk başta inanmadım. "Bu bot sürekli çalışıyor, daha önce sorun yoktu ki?" diye düşündüm. lsof komutuyla süreci kontrol ettiğimde gördüğüm manzara içler acısıydı. Binlerce TCP socket CLOSE_WAIT durumunda, öylece bekliyordu. StackOverflow'da bile bu kadar net bir kaynak yoktu aslında, direkt sistemin bana bağırışıydı.
Çözüm: finally Bloğu Kurtarıcım Oldu
Sorun, uzun süreli (long-running) bir proses olan botumda, bir try-except içinde socket işlemleri yapıp, istisna (exception) atıldığında .close() metodunun çağrılmamasıydı. Her şey yolunda giderse kapatıyordu ama bir hata olunca socket havada kalıyordu. Çözüm basitti ama etkiliydi: finally bloğu.
Alınan Ders ve Sistem Limitleri
Bu olay bana iki önemli şey öğretti. Birincisi, resource'ları (kaynakları) açtığın yerde kapatmayı garantile. İkincisi, ulimit değerlerini bilmek. Sunucudaki ulimit -n değeri düşükse, daha az socketle bu hatayı alabilirsin. Belki geçici çözüm olarak artırabilirsin, ama asıl çözüm kodun doğru yazılması.
Siz de benzer bir "kaynak sızıntısı" (resource leak) yaşadınız mı? Özellikle long-running process'lerde başka hangi tuzaklara düşmüştünüz? "with" statement kullanmak her zaman daha mı iyi?
İlk başta inanmadım. "Bu bot sürekli çalışıyor, daha önce sorun yoktu ki?" diye düşündüm. lsof komutuyla süreci kontrol ettiğimde gördüğüm manzara içler acısıydı. Binlerce TCP socket CLOSE_WAIT durumunda, öylece bekliyordu. StackOverflow'da bile bu kadar net bir kaynak yoktu aslında, direkt sistemin bana bağırışıydı.
Bash:
lsof -p <pid> | wc -l
Sorun, uzun süreli (long-running) bir proses olan botumda, bir try-except içinde socket işlemleri yapıp, istisna (exception) atıldığında .close() metodunun çağrılmamasıydı. Her şey yolunda giderse kapatıyordu ama bir hata olunca socket havada kalıyordu. Çözüm basitti ama etkiliydi: finally bloğu.
Python:
sock = None
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
# ... veri gönder/al ...
except socket.error as e:
print(f"Socket hatası: {e}")
finally:
if sock:
sock.close() # BU SATIR HAYAT KURTARDI!
Bu olay bana iki önemli şey öğretti. Birincisi, resource'ları (kaynakları) açtığın yerde kapatmayı garantile. İkincisi, ulimit değerlerini bilmek. Sunucudaki ulimit -n değeri düşükse, daha az socketle bu hatayı alabilirsin. Belki geçici çözüm olarak artırabilirsin, ama asıl çözüm kodun doğru yazılması.
Siz de benzer bir "kaynak sızıntısı" (resource leak) yaşadınız mı? Özellikle long-running process'lerde başka hangi tuzaklara düşmüştünüz? "with" statement kullanmak her zaman daha mı iyi?