让工作队列和RPC一起工作

时间:2016-04-07 13:03:32

标签: c# rabbitmq

我开始使用RabbitMQ并且在完成教程之后,我现在正试图让它以我需要的方式工作,并且我遇到了困难。我的设置是我需要能够先创建一个RPC,然后根据客户端将(或不会)发送另一条消息到工作队列的响应(我不需要回应客户)。不幸的是,我努力让它一起工作似乎并没有按照我想要的方式进行。在服务器端,我有这样的事情(我已经尝试了很多变化都有相同的问题):

var factory = new ConnectionFactory() { HostName = "localhost" };
connection = factory.CreateConnection();
channel = connection.CreateModel();
channel.ExchangeDeclare(exchange: "jobs", type: "direct", durable: true);

// I started with a named queue, not sure if that's better or worse for this
var queueName = channel.QueueDeclare().QueueName;

channel.QueueBind(queue: queueName, 
    exchange: "jobs",
    routingKey: "saveJob_queue");

channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);

var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
    // save stuff that was sent with the saveJob_queue routingKey
}

channel.BasicConsume(queue: queueName, 
    noAck: false,
    consumer: consumer);

// set up channel for RPC
// Not sure if this has to have another channel, but it wasn't working on the same channel either
rpcChannel = connection.CreateModel();
var rpcQueueName = rpcChannel.QueueDeclare().QueueName;

rpcChannel.QueueBind(queue: rpcQueueName,  
    exchange: "jobs",
    routingKey: "rpc_CheckJob_queue");

var rpcConsumer = new EventingBasicConsumer(rpcChannel);

rpcConsumer.Received += (model, ea) =>
{
    // do my remote call and send back a response
}

我遇到的问题是,使用路由密钥jobs发送到rpc_CheckJob_queue交换机的邮件仍然会在第一个频道上触发Recieved事件,尽管它应该是只接收saveJob_queue个路由。我可以检查该处理程序中的ea.RoutingKey并忽略这些消息,但我不知道他们最初是如何以及为什么会这样做的?

设置连接的正确方法是什么,以便它可以接收工作队列消息和RPC消息并正确处理它们?

2 个答案:

答案 0 :(得分:0)

由于您没有为队列指定名称,我怀疑您将获得两次相同的队列。所以我认为正在发生的事情就是这个。

工作 - > saveJob_queue - > SomeSystemQueue
工作 - > rpc_CheckJob_queue - > SomeSystemQueue

尝试选择两个单独的队列名称,然后再次运行代码。 所以不要这样:

var queueName = channel.QueueDeclare().QueueName;

channel.QueueBind(queue: queueName, 
    exchange: "jobs",
    routingKey: "saveJob_queue");

有:

var name = "Queue A";
channel.QueueDeclare(name);
channel.QueueBind(queue: queueName, 
        exchange: "jobs",
        routingKey: "saveJob_queue");

然后将您的第二个队列命名为其他内容,然后尝试。

答案 1 :(得分:0)

所以我放弃了这一点,决定只过滤Received事件。我认为问题在于RabbitMQ在频道上只有Received个事件,而在队列上没有。因此,Received事件会受到任何影响。所以现在我有了这个:

channel.QueueDeclare(queue: queueName,  
         durable: true,
         exclusive: false,
         autoDelete: false,
         arguments: null);

channel.QueueDeclare(queue: rpcQueueName,
         durable: false,
         exclusive: false,
         autoDelete: false,
         arguments: null);

channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);

var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
    switch (ea.RoutingKey)
    {
        case queueName:
            SaveJob(ea);
            break;
        case rpcQueueName:
            CheckJob(ea);
            break;
    }
    channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
};

channel.BasicConsume(queue: queueName, 
    noAck: false,
    consumer: consumer);

channel.BasicConsume(queue: rpcQueueName,
                     noAck: false,
                     consumer: consumer);

我愿意接受更好的建议,因为这似乎有点过时了。

所以发送只是:

var properties = channel.CreateBasicProperties();
properties.Persistent = true;

channel.BasicPublish(exchange: "",
                     routingKey: queueName,
                     basicProperties: properties,
                     body: body);

为正常工作而且:

var corrId = Guid.NewGuid().ToString();
var props = channel.CreateBasicProperties();
props.ReplyTo = replyQueueName;
props.CorrelationId = corrId;

var messageBytes = Encoding.UTF8.GetBytes(msg);
channel.BasicPublish(exchange: "",
                     routingKey: rpcQueueName,
                     basicProperties: props,
                     body: messageBytes);

while (true)   
{
    var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
    if (ea.BasicProperties.CorrelationId == corrId)
    {
        return ea.Body != null && ea.Body.Any() ? BitConverter.ToInt32(ea.Body,0) : (int?)null;
    }
}

对于RPC。