RabbitMQ 3.5 и приоритет сообщения

RabbitMQ 3.5 сейчас поддерживает приоритет сообщения; Однако я не могу привести рабочий пример. Я разместил свой код ниже. Он включает в себя результат, который я ожидаю, и результат, который я на самом деле. Мне было бы интересно больше документации и/или рабочего примера.

Итак, мой вопрос вкратце: как получить приоритет сообщения для работы в Rabbit 3.5.0.0?

издатель:

using System;
using RabbitMQ.Client;
using System.Text;
using System.Collections.Generic;

class Publisher
{

    public static void Main()
    {
        var factory = new ConnectionFactory() { HostName = "localhost" };
        using (var connection = factory.CreateConnection())
        {
            using (var channel = connection.CreateModel())
            {
                IDictionary <String , Object> args = new Dictionary<String,Object>() ;
                args.Add(" x-max-priority ", 10);
                channel.QueueDeclare("task_queue1", true, false, true, args);

                for (int i = 1 ; i<=10; i++ )
                {
                    var message = "Message";
                    var body = Encoding.UTF8.GetBytes(message + " " + i);
                    var properties = channel.CreateBasicProperties();
                    properties.SetPersistent(true);
                    properties.Priority = Convert.ToByte(i);
                    channel.BasicPublish("", "task_queue1", properties, body);
                }
            }
        }
    }
}

потребитель:

using System;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
using System.Threading;
using System.Collections.Generic;

namespace Consumer
{ 
    class Worker
    {
        public static void Main()
        {
            var factory = new ConnectionFactory() { HostName = "localhost" };
            using (var connection = factory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    IDictionary<String, Object> args = new Dictionary<String, Object>();                      
                    channel.BasicQos(0, 1, false);
                    var consumer = new QueueingBasicConsumer(channel);
                    IDictionary<string, object> consumerArgs = new Dictionary<string, object>();
                    channel.BasicConsume( "task_queue1", false, "", args, consumer);
                    Console.WriteLine(" [*] Waiting for messages. " +
                                      "To exit press CTRL+C");
                    while (true)
                    {
                        var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
                        var body = ea.Body;
                        var message = Encoding.UTF8.GetString(body);
                        Console.WriteLine(" [x] Received {0}", message);
                        channel.BasicAck(ea.DeliveryTag, false);
                    }
                }
            }
        }
    }
}

фактическое вывод:

[*] Waiting for messages. To exit press CTRL+C
[x] Received Message 1
[x] Received Message 2
[x] Received Message 3
[x] Received Message 4
[x] Received Message 5
[x] Received Message 6
[x] Received Message 7
[x] Received Message 8
[x] Received Message 9
[x] Received Message 10

ожидаемый результат:

[*] Waiting for messages. To exit press CTRL+C
[x] Received Message 10
[x] Received Message 9
[x] Received Message 8
[x] Received Message 7
[x] Received Message 6
[x] Received Message 5
[x] Received Message 4
[x] Received Message 3
[x] Received Message 2
[x] Received Message 1

обновление #1. Я нашел пример в Java здесь. Однако это кролик 3.4.х.х. надстройка, которая была включена в 3.5. Единственное различие, которое я вижу, заключается в том, что они выражают приоритет как int, а мой-байт. Но я чувствую, что это отвлекающий маневр. Я немного растерян.

3 ответов


Ну, я решил это. Это была глупая ошибка. Я написал:

args.Add(" x-max-priority ", 10);

это должно было быть

args.Add("x-max-priority", 10);

Я оставлю это, чтобы другие люди могли иметь рабочий пример очередей приоритетов Rabbitmq 3.5 В C#.


аналогичная реализация очереди приоритетов RabbitMq в узле js

установить amqplib

чтобы проверить, мы обязаны установили amqplib

npm install amqplib

издатель (отправить.в JS)

#!/usr/bin/env node

var amqp = require('amqplib/callback_api');

function bail(err, conn) {
  console.error(err);
  if (conn) conn.close(function() { process.exit(1); });
}

function on_connect(err, conn) {
  if (err !== null) return bail(err);

  // name of queue
  var q = 'hello';
  var msg = 'Hello World!';
  var priorityValue = 0;

  function on_channel_open(err, ch) {
    if (err !== null) return bail(err, conn);
    // maxPriority : max priority value supported by queue
    ch.assertQueue(q, {durable: false, maxPriority: 10}, function(err, ok) {
      if (err !== null) return bail(err, conn);

      for(var index=1; index<=100; index++) {
             priorityValue = Math.floor((Math.random() * 10));
             msg = 'Hello World!' + ' ' + index + ' ' + priorityValue;
             ch.publish('', q, new Buffer(msg), {priority: priorityValue});
             console.log(" [x] Sent '%s'", msg);
      }

      ch.close(function() { conn.close(); });
    });
  }

  conn.createChannel(on_channel_open);
}

amqp.connect(on_connect);

подписчик (receive.в JS)

#!/usr/bin/env node

var amqp = require('amqplib/callback_api');

function bail(err, conn) {
  console.error(err);
  if (conn) conn.close(function() { process.exit(1); });
}

function on_connect(err, conn) {
  if (err !== null) return bail(err);
  process.once('SIGINT', function() { conn.close(); });

  var q = 'hello';

  function on_channel_open(err, ch) {
    ch.assertQueue(q, {durable: false, maxPriority: 10}, function(err, ok) {
      if (err !== null) return bail(err, conn);
      ch.consume(q, function(msg) { // message callback
        console.log(" [x] Received '%s'", msg.content.toString());
      }, {noAck: true}, function(_consumeOk) { // consume callback
        console.log(' [*] Waiting for messages. To exit press CTRL+C');
      });
    });
  }

  conn.createChannel(on_channel_open);
}

amqp.connect(on_connect);

Run:

node send.js

он создаст очередь с именем "hello" и затопит ее образцами сообщений "1000", используя обмен AMQP по умолчанию.

node receive.js

он будет действовать как потребитель, чтобы подписаться на сообщения, ожидающие в очереди.


еще одна возможность (для будущих искателей)

метод "Push" доставки сообщений, похоже, не уважает приоритет.

http://rabbitmq.docs.pivotal.io/35/rabbit-web-docs/dotnet-api-guide.html.html

на ниже является цитатой из URL-адреса выше. Я выделил самую важную часть.

получение сообщений по подписке ("push API")

другой способ получения сообщений создать подписку с помощью интерфейса IBasicConsumer. сообщения будут доставляться автоматически по мере их поступления, а не запрашиваться заранее. один из способов реализации потребителя-использовать класс удобства EventingBasicConsumer, который отправляет поставки и другие события жизненного цикла потребителя как события C#:

var consumer = new EventingBasicConsumer(channel);
consumer.Received += (ch, ea) =>
                {
                    var body = ea.Body;
                    // ... process the message
                    ch.BasicAck(ea.DeliveryTag, false);
                };  
String consumerTag = channel.BasicConsume(queueName, false, consumer);

при переходе на метод "тянуть" приоритет, по-видимому, соблюдается. Однако в цитата ниже (из того же url выше), похоже, есть компромисс (что у меня жирным шрифтом)

выборка отдельных сообщений ("pull API") Для получения отдельных сообщений используйте IModel.BasicGet. Возвращаемое значение является экземпляром BasicGetResult, из которого можно извлечь информацию заголовка (свойства) и тело сообщения:

bool noAck = false;
BasicGetResult result = channel.BasicGet(queueName, noAck);
if (result == null) {
    // No message available at this time.
} else {
    IBasicProperties props = result.BasicProperties;
    byte[] body = result.Body;
    ...

поскольку noAck = false выше, вы также должны вызвать IModel.BasicAck к подтвердите, что вы успешно получили и обработали сообщение:

    ...
    // acknowledge receipt of the message
    channel.BasicAck(result.DeliveryTag, false);
}

обратите внимание, что извлечение сообщений с помощью этого API относительно неэффективно. если вы предпочитаете RabbitMQ для передачи сообщений клиенту, см. Следующий раздел.

(раздел " далее "в этом случае приведет вас к методу" push " в верхней части этого сообщения)