FirebirdSQL / NETProvider

Firebird ADO.NET Data Provider
https://www.firebirdsql.org/en/net-provider/
Other
159 stars 65 forks source link

InvalidOperationException 'Connection pool is full' when network connection fails and connection timeout is less than 22 seconds #1071

Closed pjenei closed 1 year ago

pjenei commented 2 years ago

This issue is very similar to #914 but in a networked environment. (My sample code is based on the code by silveraid) I try to connect to an unreachable Firebird server over TCP/IP so the connection fails (real world scenario was a VPN outage between my application server and the database server). When the connection timeout is set lower than 22 s (the exact value may change in different environments), TimeoutException is raised and the connection pool fills up with busy connections. When the connection timeout is at least 22 s, FbException is raised and connection pool behaves normally. Environment: Windows 11, VS 2022, .NET 6, FirebirdSql.Data.FirebirdClient 9.0.2

Sample code to reproduce issue I created two test rounds with different timeout setting to show the difference. Connection string can be any valid connection string that point to an inaccessible computer. Maybe you have to increase timeout value in the first run to see the difference.

using FirebirdSql.Data.FirebirdClient;

int retries = 0; while (true) { try { using FbConnection con = new( "User=SYSDBA;Password=masterkey;MaxPoolSize=3;ConnectionTimeout=22;Database=C:\Database\testdb.fdb;DataSource=192.168.100.100;Port=3050;Dialect=3;"); await con.OpenAsync(); await con.CloseAsync(); } catch (Exception ex) { Console.WriteLine($"Connection failed: {ex.Message} Exception: {ex.GetType().Name}"); if (retries++ >= 4) { Console.WriteLine("Giving up...."); break; } } } retries = 0; while (true) { try { using FbConnection con = new( "User=SYSDBA;Password=masterkey;MaxPoolSize=3;ConnectionTimeout=15;Database=C:\Database\testdb.fdb;DataSource=192.168.100.100;Port=3050;Dialect=3;"); await con.OpenAsync(); await con.CloseAsync(); } catch (Exception ex) { Console.WriteLine($"Connection failed: {ex.Message} Exception: {ex.GetType().Name}"); FbConnection.ClearAllPools(); if (retries++ >= 4) { Console.WriteLine("Giving up...."); break; } } }

Output of the test run Connection failed: Unable to complete network request to host "192.168.100.100". Exception: FbException Connection failed: Unable to complete network request to host "192.168.100.100". Exception: FbException Connection failed: Unable to complete network request to host "192.168.100.100". Exception: FbException Connection failed: Unable to complete network request to host "192.168.100.100". Exception: FbException Connection failed: Unable to complete network request to host "192.168.100.100". Exception: FbException Giving up.... Connection failed: Timeout while connecting. Exception: TimeoutException Connection failed: Timeout while connecting. Exception: TimeoutException Connection failed: Timeout while connecting. Exception: TimeoutException Connection failed: Connection pool is full. Exception: InvalidOperationException Connection failed: Connection pool is full. Exception: InvalidOperationException Giving up....

cincuranet commented 1 year ago

With your test (with tweaked timeouts) it should be fixed in this build. Can you confirm @pjenei?

pjenei commented 1 year ago

Excuse me for my late answer, @cincuranet. I downloaded and tested the build. Everything works as expected, connection pool does not fill up on timeout errors. Thank you very much for your help!

cincuranet commented 1 year ago

Fixed via 80b76d7.