SemaphoreSlim保护连接池免于耗尽

时间:2018-03-20 12:16:37

标签: c# postgresql rabbitmq .net-core npgsql

我在事件驱动架构中有一个微服务(Web API),它接收来自RabbitMQ的消息,它应该使用ADO.NET将它们保存到PostgreSQL数据库中。

不幸的是,我的连接池(目前设置为50)很快耗尽,给我这个错误信息:

The connection pool has been exhausted, either raise MaxPoolSize

我的RabbitMQ Consumer设置如下(Singleton):

public class Listener : RabbitMqConnection
{
    public AsyncEventingBasicConsumer _asyncConsumer;
    private static readonly SemaphoreSlim AsyncLock = new SemaphoreSlim(1, 1);

    public Listener()
    {
        _asyncConsumer = new AsyncEventingBasicConsumer(_channel);
        _asyncConsumer.Received += ConsumerReceived;        
    }   

    public async Task ConsumerReceived(object sender, BasicDeliverEventArgs message)
    {
        await AsyncLock.WaitAsync();
        try
        {
            //Performing logic and saving into database
            //....
            using (var ctx = ContextFactory.GetContext<PostgreSqlDatabaseContext>(_connectionString))
            {
                //Creating query with StringBuilder... 
                await ctx.Database.ExecuteSqlCommandAsync(query.ToString(), parameters);
            }

            _channel.BasicAck(message.DeliveryTag, false);
        }
        catch (DecoderFallbackException decoderFallbackException)
        {
            _logger.LogError($"...");
            _channel.BasicNack(message.DeliveryTag, false, false);
        }       
        finally {
            AsyncLock.Release();
        }       
    }
}

ContextFactory

internal class ContextFactory
{
    public static T GetContext<T>(string sqlConnection) where T : DbContext
    {
        var optionsBuilder = new DbContextOptionsBuilder<PostgreSqlDatabaseContext>();
        optionsBuilder.UseNpgsql(sqlConnection);
        return new PostgreSqlDatabaseContext(optionsBuilder.Options) as T;
    }
}

RabbitMqConnection:

public abstract class RabbitMQConnection 
{
    public  IModel _channel;
    public IBasicProperties _properties;
    public AsyncEventingBasicConsumer _asyncConsumer;
    public ConnectionFactory _factory;
    public ConnectConfiguration _connectConfiguration;
    bool isConnected = false;

    public void Connect(ConnectConfiguration connectConfiguration)
    {
        if (!isConnected)
        {
            _connectConfiguration = connectConfiguration;
            CreateFactory(_connectConfiguration);
            SetupConfiguration(_connectConfiguration.Exchange);
        }
    }

    private void CreateFactory(ConnectConfiguration config)
    {
        _factory = new ConnectionFactory
        {
            AutomaticRecoveryEnabled = true,
            DispatchConsumersAsync = true,
            UseBackgroundThreadsForIO = true,
            RequestedHeartbeat = 15,
            HostName = config.Server,
            UserName = config.UserName,
            Password = config.Password
        };

        if (!string.IsNullOrWhiteSpace(config.Vhost))
            _factory.VirtualHost = config.Vhost;
    }

    private void SetupConfiguration(string exchange)
    {
         var connection = _factory.CreateConnection();
        _channel = connection.CreateModel();

        _properties = _channel.CreateBasicProperties();
        _properties.Persistent = true;

        _channel.BasicQos(0, 10, false);
        _channel.ExchangeDeclare(exchange, "topic", true);

        isConnected = true;
    }
}

我无法理解为什么我一直收到这个错误。具有SemaphoreSlimWaitAsync()的{​​{1}}是否会阻止Release()方法运行逻辑?

0 个答案:

没有答案