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 " в верхней части этого сообщения)