簡體   English   中英

Rabbit MQ句柄取消令牌

[英]Rabbit MQ handle cancellation token

我正在關注本文( http://www.jarloo.com/listening-to-rabbitmq-events/ ),以便在控制台應用程序上使用消息,目前我擔心當用戶按下CTRL + C並退出時會發生什么情況應用程序。

至少,我希望它在退出程序之前完成對當前消息和ack的處理。 我對RabbitMQ的新手感到困惑,我該如何實現該代碼。

我了解該channel.BasicConsume(queueName,true,消費者); 正在阻塞線程。

任何幫助將不勝感激。

對於該問題,您嘗試解決的只有我能想到的就是將其視為事務。.僅當您收到消息時,對其進行完全處理並發送回Ack,才認為該事務已完成。

如果您首先處理該消息,並且有人在Ack之前終止了該應用程序,則它將再次排隊,而當我們重新啟動該應用程序時,它將再次得到處理。

與此相反,如果您先確認然后嘗試處理該消息,但有人終止了該應用程序,則您將丟失該消息。

因此,看起來好像在考慮整個過程,因為事務將使它正常工作,或者另一個選擇是照顧再次處理同一消息。

這是我設法實現的目標,但不確定是最好的方法還是有所改進。 我尚未使用cancellingToken,但不確定是否可以使用它。

在我的控制台上,我得到了預期的結果(請參見屏幕截圖)

在此處輸入圖片說明

public abstract class QueueConnection : IDisposable
{
    internal IConnection _connection;
    internal IModel _model;
    internal IBasicProperties _properties;
    internal RabbitMQSettings _settings;
    internal protected object _modelLock = new Object();

    public QueueConnection(IOptions<RabbitMQSettings> queueConfig)
    {
        _settings = queueConfig.Value;
    }

    internal bool CreateModel(string queueName)
    {
        if (string.IsNullOrEmpty(queueName))
        {
            throw new ArgumentException("The queue name has to be specified before.");
        }

        lock (_modelLock)
        {
            if (!IsConnected) Connect();
            if (_model == null || _model.IsClosed)
            {
                _model = _connection.CreateModel();

                // When AutoClose is true, the last channel to close will also cause the connection to close. 
                // If it is set to true before any channel is created, the connection will close then and there.
                _connection.AutoClose = true;

                // Configure the Quality of service for the model. Below is how what each setting means.
                // BasicQos(0="Dont send me a new message untill I’ve finshed",  1= "Send me one message at a time", false ="Apply to this Model only")
                _model.BasicQos(0, 50, false);

                const bool durable = true, queueAutoDelete = false, exclusive = false;

                _model.QueueDeclare(queueName, durable, exclusive, queueAutoDelete, null);
                _properties = RabbitMQProperties.CreateDefaultProperties(_model);
            }
        }

        return true;
    }

    public void Connect()
    {
        var connectionFactory = new ConnectionFactory
        {
            HostName = _settings.HostName,
            UserName = _settings.UserName,
            Password = _settings.Password,
        };


        if (_settings.Port.HasValue) connectionFactory.Port = _settings.Port.Value;
        if (_settings.Heartbeat.HasValue) connectionFactory.RequestedHeartbeat = _settings.Heartbeat.Value;
        if (!string.IsNullOrEmpty(_settings.VirtualHost)) connectionFactory.VirtualHost = _settings.VirtualHost;


        _connection = connectionFactory.CreateConnection();
    }

    public bool IsConnected
    {
        get { return _connection != null && _connection.IsOpen; }
    }

    public object GetConnection()
    {
        return _connection;
    }

    public void Disconnect()
    {
        if (_connection != null) _connection.Dispose();
    }

    void IDisposable.Dispose()
    {
        Disconnect();
    }
}

QueueConsumer類

public class QueueConsumer : QueueConnection, IQueueConsumer
{
    private EventingBasicConsumer consumer;
    public QueueConsumer(IOptions<RabbitMQSettings> queueConfig)
        :base(queueConfig) {}

    public void ReadFromQueue(Action<string, ulong> onDequeue, Action<Exception, ulong> onError)
    {
        ReadFromQueue(onDequeue, onError, _settings.QueueName);
    }

    public void ReadFromQueue(Action<string, ulong> onDequeue, Action<Exception, ulong> onError, string queueName)
    {

        CreateModel(queueName);

        consumer = new EventingBasicConsumer(_model);

        // Receive the messages
        consumer.Received += (o, e) =>
        {
            try
            {
                var queueMessage = Encoding.UTF8.GetString(e.Body);
                onDequeue.Invoke(queueMessage, e.DeliveryTag);
            }
            catch (Exception ex)
            {
                onError.Invoke(ex, e.DeliveryTag);
            }
        };

        // if the consumer shutdown reconnects to rabbitmq and begin reading from the queue again.
        consumer.Shutdown += (o, e) =>
        {
            CreateModel(queueName);
            ReadFromQueue(onDequeue, onError, queueName);
        };

        _model.BasicConsume(queueName, false, consumer);

    }

    public void AcknowledgeMessage(ulong deliveryTag)
    {
        if (!IsConnected) Connect();
        CreateModel(_settings.QueueName);
        _model.BasicAck(deliveryTag, false);
    }

    public void StopListening()
    {
        _model.BasicCancel(consumer.ConsumerTag);
    }
}

主班

    static ManualResetEvent _quitEvent = new ManualResetEvent(false);


    public static void Main(string[] args)
    {

        IServiceCollection services = new ServiceCollection();
        ConfigureServices(services);

        var serviceProvider = services.BuildServiceProvider();

        Console.WriteLine($"[{DateTime.UtcNow.ToString("dd/MM/yyyy HH:mm:ss")}] -> Worker role started");

        var listener = serviceProvider.GetService<IMessageProcessor>();

        Console.CancelKeyPress += (sender, eArgs) =>
        {
            listener.OnStop();

            Console.WriteLine($"[{DateTime.UtcNow.ToString("dd/MM/yyyy HH:mm:ss")}] -> Worker role finished");
            _quitEvent.Set();
            eArgs.Cancel = true;
        };

        _quitEvent.WaitOne();
    }

    private static IConfigurationRoot GetConfiguration()
    {
        // Build appsetting.json configuration
        var environment = Environment.GetEnvironmentVariable("Environment");

        return new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{environment}.json", optional: true)
            .AddEnvironmentVariables().Build();
    }

    private static void ConfigureServices(IServiceCollection services)
    {
        IConfigurationRoot configuration = GetConfiguration();
        services.AddSingleton<IConfigurationRoot>(configuration);

        // Support typed options
        services.AddOptions();

        services.Configure<RabbitMQSettings>(configuration.GetSection("RabbitMQConfig"));

        services.AddSingleton<IQueueConsumer, QueueConsumer>();
        services.AddScoped<IMessageProcessor, MessageProcessor>();

    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM