public Task <DbConnection> GetDbConnectionAsync(string poolKey) { if (disposedValue) { throw new ObjectDisposedException(nameof(SqlConnectionPoolManager)); } if (!_poolOptions.ContainsKey(poolKey)) { throw new KeyNotFoundException(); } var pool = _pools[poolKey]; PooledDbConnectionWrapper availableConn = null; do { var hasConn = TryGetConnection(pool, out availableConn, out _); if (!hasConn && !SetupNewConnection(poolKey)) { break; } }while (availableConn?.DbConnection.State != ConnectionState.Open); return(Task.FromResult(availableConn?.DbConnection)); }
public Task <bool> TryReturnToPoolAsync(DbConnection connection) { if (disposedValue || !connection.CanOpen()) { return(Task.FromResult(false)); } if (connection is SqlConnection == false) { throw new InvalidOperationException("Unsupported connection"); } var sqlConn = connection as SqlConnection; var poolKey = GetPoolKeyFromConnStr(sqlConn.ConnectionString); if (!_poolOptions.ContainsKey(poolKey)) { return(Task.FromResult(false)); } var wrapper = new PooledDbConnectionWrapper(connection, poolKey); return(TryReturnToPoolAsync(wrapper)); }
private async Task DbConn_StateChangeAsync(object sender, StateChangeEventArgs e, PooledDbConnectionWrapper wrapper) { if (disposedValue || wrapper.DbConnection.IsOpening() || HasExceededLifetime( _connInfos[(wrapper.DbConnection as SqlConnection).ClientConnectionId], _poolOptions[wrapper.PoolKey])) { return; } await TryReturnToPoolAsync(wrapper); }
private bool TryGetConnection(ConcurrentQueue <PooledDbConnectionWrapper> pool, out PooledDbConnectionWrapper wrapper, out ConnectionInfo connectionInfo) { connectionInfo = default; var hasConn = pool.TryDequeue(out wrapper); if (hasConn) { _connInfos.Remove((wrapper.DbConnection as SqlConnection).ClientConnectionId, out connectionInfo); wrapper.IsInPool = false; } return(hasConn); }
private bool SetupNewConnection(string poolKey) { if (disposedValue) { return(false); } lock (_poolsLock) { var pool = _pools[poolKey]; var poolOption = _poolOptions[poolKey]; if (HasFullOfConnections(pool, poolOption)) { return(false); } try { var dbConn = new SqlConnection(poolOption.ConnectionString); var wrapper = new PooledDbConnectionWrapper(dbConn, poolKey); dbConn.StateChange += async(sender, e) => await DbConn_StateChangeAsync(sender, e, wrapper); dbConn.Open(); AddNewConnection(pool, wrapper); } catch (Exception ex) { NewConnectionError?.Invoke(ex, poolKey); throw ex; } } return(true); }
private void AddNewConnection(ConcurrentQueue <PooledDbConnectionWrapper> pool, PooledDbConnectionWrapper wrapper) { pool.Enqueue(wrapper); _connInfos[(wrapper.DbConnection as SqlConnection).ClientConnectionId] = new ConnectionInfo() { CreatedTime = DateTime.UtcNow, Wrapper = wrapper }; wrapper.IsInPool = true; }
private Task <bool> TryReturnToPoolAsync(PooledDbConnectionWrapper wrapper) { if (disposedValue || !wrapper.DbConnection.CanOpen()) { return(Task.FromResult(false)); } return(Task.Run(() => { if (disposedValue || !wrapper.DbConnection.CanOpen()) { return false; } var poolKey = wrapper.PoolKey; var poolOption = _poolOptions[poolKey]; var pool = _pools[poolKey]; var inPool = false; RetryAction((retryCount) => { try { lock (_poolsLock) { if (!HasFullOfConnections(pool, poolOption)) { if (wrapper.IsInPool) { if (HasExceededLifetime( _connInfos[(wrapper.DbConnection as SqlConnection).ClientConnectionId], poolOption)) { return true; } if (!wrapper.DbConnection.IsOpening() && wrapper.DbConnection.CanOpen()) { wrapper.DbConnection.Open(); } } else { if (!wrapper.DbConnection.IsOpening() && wrapper.DbConnection.CanOpen()) { wrapper.DbConnection.Open(); } AddNewConnection(pool, wrapper); } inPool = true; } return true; } } catch (Exception ex) { TryReturnToPoolError?.Invoke(ex, retryCount); return false; } }, poolOption); return inPool; })); }