C# 让工作队列和RPC一起工作

C# 让工作队列和RPC一起工作,c#,rabbitmq,C#,Rabbitmq,我开始使用RabbitMQ,在跟随教程之后,我现在正试图让它以我需要的方式工作,我遇到了困难。我的设置是,我需要能够首先进行RPC,然后根据客户机将(或不会)向工作队列发送另一条消息的响应(在工作队列中,我不需要向客户机发送响应)。不幸的是,我的努力,使这一起工作似乎没有工作的方式,我想要的。在服务器端,我有类似的东西(我尝试了许多变体,都有相同的问题): 我遇到的问题是,使用路由键rpc\u CheckJob\u queue发送到jobs交换的消息仍然会触发第一个通道上的received事件,

我开始使用RabbitMQ,在跟随教程之后,我现在正试图让它以我需要的方式工作,我遇到了困难。我的设置是,我需要能够首先进行RPC,然后根据客户机将(或不会)向工作队列发送另一条消息的响应(在工作队列中,我不需要向客户机发送响应)。不幸的是,我的努力,使这一起工作似乎没有工作的方式,我想要的。在服务器端,我有类似的东西(我尝试了许多变体,都有相同的问题):

我遇到的问题是,使用路由键
rpc\u CheckJob\u queue
发送到
jobs
交换的消息仍然会触发第一个通道上的
received
事件,尽管它应该只接收
saveJob\u queue
路由。我可以在该处理程序中检查ea.RoutingKey,然后忽略这些消息,但我不明白它们最初是如何以及为什么会出现在那里的


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

由于您没有为队列指定名称,我怀疑您两次收到相同的队列。所以我认为发生的事情本质上是这样的

作业-->保存作业\u队列-->SomeSystemQueue
作业-->rpc\U检查作业\U队列-->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");

然后将第二个队列命名为其他名称,然后尝试此操作。

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

作业-->保存作业\u队列-->SomeSystemQueue
作业-->rpc\U检查作业\U队列-->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");

然后给你的第二个队列起个别的名字,试试看。

所以我放弃了这个,决定只过滤
接收的
事件。我认为问题在于RabbitMQ在通道上只有一个
接收的
事件,而在队列上没有。因此,
接收的
事件会以任何方式命中。现在我有了这个:

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.

所以我放弃了这个,决定只过滤
接收的
事件。我认为问题在于RabbitMQ在通道上只有一个
接收的
事件,而在队列上没有。因此,
接收的
事件会以任何方式命中。现在我有了这个:

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.

您是否缺少
rpcChannel.BasicConsume(rpcqueName:queueName,
)之类的内容?另外,如果您可以发布发送消息的代码,是否缺少
rpcChannel.BasicConsume之类的内容(rpcQueueName:queueName,
?另外,如果您可以发布发送消息的代码,我最初确实有两个队列的名称(当然不同),但有相同的问题。好的。你可能想切换回那个,只是为了完全排除这个问题。你可以发布你的发送逻辑吗?这样每个人都可以看到你正在寻址的路由密钥,依此类推。我最初有两个队列的名称(当然不同),但也有同样的问题。好的。你可能想切换回那个,只是为了完全排除这个问题。你可以发布你的发送逻辑吗?这样每个人都可以看到你正在寻址的路由密钥,等等。