System.InvalidOperationException

Uzunca bir süredir hakkında yazmak istediğim bir "exception"dı bu, ancak henüz fırsat bulabildim. Tam hata mesajımız şu şekildedir:

System.InvalidOperationException: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool.

This may have occurred because all pooled connections were in use and max pool size was reached.

Aslında hata mesajı yeterince açık ama "InvalidOperationException" tabiri biraz yanıltıcı olabiliyor. Hatanın nedeni çok net: havuzda bağlantı kalmamış.

Veritabanı bağlantılarında (ister SQL Server olsun, ister Oracle veya başka bir veritabanı), genel olarak bir bağlantı havuzu kullanılır; veritabanına her istek için yeniden bağlantı açılıp kapatılmaz. Bu havuzun da bir kapasitesi vardır. Örneğin SQL Server için bunun ön tanımlı değeri 100'dür (max pool size değeri). Yani havuzda herhangi bir anda en fazla 100 adet bağlantı bulunur ve veritabanına gidecek tüm işler bu havuzdan bir bağlantı alıp, veritabanı işini yapıp, sonra tekrar havuza bırakırlar.

Şimdi bu senaryoda ters gidebilecek bazı şeyler var: İsteklerin gelme hızı veritabanından yanıt alma hızımızda fazla olursa, bir süre sonra havuzda bağlantı kalmayacaktır. Bu durumda yeni gelecek olan bir istek 15 saniye boyunca havuza bağlantı dönmesini bekler (connect timeout süresi kadar). İşte tam da bu süre sonunda havuz hala boşsa yukarıdaki exception alınır.

ÇÖZÜM:

Bu tür bir sorun yaşadığımızda bağlantı havuzunun ebatını artırabiliriz. Bağlantı cümlesine "max pool size" parametresini ekleyip buna 100'den büyük bir değer vermek yeterli olacaktır. Ancak bu değeri artırırken, bunun veritabanına eşzamanlı daha fazla istek gönderilmesi anlamına geleceğini, yani veritabanındaki yükü artıracağını unutmamak gerekir. Bazı durumlarda bu, veritabanının daha da yavaş yanıt vermesine ve durumun daha da kötüleşmesine neden olabilir.

Veritabanı bağlantılarını kullanırken dikkat etmemiz gereken çok önemli bir nokta vardır: İşi biten bağlantı, eğer Close() veya Dispose () metotlarından birini çağırırsak, hemen havuza geri döner. Eğer baglantıyı kapatmayı unutmuşsak, bu durumda bu bağlantı ilk hemen havuza dönemez, GC tarafından temizlenmeyi bekler ve havuza dönme süresi uzar. Bu da, yukarıdaki sorunu yaşama ihtimalimizi kat kat artıracaktır. "Max pool size" değerini 5000 verdiği halde bu hatayı zaman zaman alan uygulamalarla karşılaştım. Bu nedenle daha uygulamayı geliştiriken açılan her bağlantının mutlaka kapatıldığından emin olmalıyız. Bağlantıyı açtıktan sonra oluşabilecek sorunlara karşı try/catch bloğu kullanıp, finally altında bağlantıyı kapatmalıyız. Bir diğer yöntem de using kullanmak olacaktır.

Özetle, kod geliştiriken göz ardı edeceğimiz ufak şeyler, uygulama yük altına girince büyük sorunlar olarak karşımıza çıkabilir. Sadece veritabanı bağlantıları anlamında değil, her türlü nesneyle işimiz bittiğinde, eğer nesnenin bir "Close()" metodu varsa çağırmalıyız. Ve bunu işimiz biter bitmez yaptığımızdan, ve bunu engelleyecek bir sorun olmayacağından emin olmalıyız.

CENK İŞCAN