Getting to grips with EasyNetQ – Part 3 – Request Response


This post is about fleshing out the Request Response implementation of EasyNetQ.

Request class

using System;
using EasyNetQ;
using SubscribeWithLoggerConsoleAppNamespace;

namespace RequestClosureConsoleAppNamespace
{
    class Program
    {
        static void Main()
        {
            var logger = new MyLogger();

            using (var bus = RabbitHutch.CreateBus("host=Ubuntu-12"))
            {
                var myRequest = new MyRequest();

                using (var publishChannel = bus.OpenPublishChannel())
                {
                    for (var i = 0; i < 5; i++)
                    {
                        myRequest.Text = "Send to Response Server " + i;
                        publishChannel.Request<MyRequest, MyResponse>(myRequest, response =>
                                                                                logger.InfoWrite(
                                                                                     "Got response: {0}", response.Text));                        
                    }
                    Console.ReadKey();
                }
            }
        }
    }
}

The code highlighted in blue is the interesting part because it again assumes that there is some response code listening in to the incoming requests.

Upon running this code, this is what happens:

ENQ-RequestRunOverviewAn exhange has been added but when you look at the details of the exchange added, you’ll see that it’s different to when we run “Publish” code.

ENQ-RequestExchangeFirst of all, the name of the exchange doesn’t follow the same pattern and is simply named “easy_net_q_rpc”. The other difference is the fact that the exchange type is not “topic” but is “direct” instead.

The behaviour while running this code differs in the fact that “queues” are actually created when sending data:

ENQ-QueuesCreatedFollowingRequestIf you look at the names of the queues created, you’ll notice that they are named “easynetq.response.xxxxxx”. The fact that they are contain “response” and the fact that the “Ready” and “Total” columns are all 0 would indicate that these queues would be used for the Response code to send data to. However, when you look at the details in each queue, you will see that none of the queues is bound to the newly created exchange i.e. “easy_net_q_rpc” and they are in fact bound to the default exchange.

ENQ-RandomQueueBinding

This was, to say the least, quite puzzling. Hence, I asked about it on the forums and here is the answer from Mike Hadlow:

Each request creates a short lived temporary queue. They can only be consumed from the requester, but they are bound to an exchange 
that the responder can publish to. Each gets one message (the response), which is swiftly consumed, so you are unlikely to see the 
message on the queue.
Because you end up with 5 consumers all bound to different queues, there's no real order. It's down to whichever RabbitMQ sends first.

Upon exiting the console application, all the queues created by the latter are removed although the exchange created does remain.

Response class

using System;
using EasyNetQ;
using RequestClosureConsoleAppNamespace;
using SubscribeWithLoggerConsoleAppNamespace;

namespace ResponseClosureConsoleAppNamespace
{
    class Program
    {
        static void Main()
        {
            var logger = new MyLogger();
            Func<MyRequest, MyResponse> respond = request =>
                {
                    logger.InfoWrite("Received {0} ", request.Text);
                    return new MyResponse
                        {
                            Text = "Responding to " + request.Text
                        };
                };

            using (var bus = RabbitHutch.CreateBus("host=Ubuntu-12"))
            {
                bus.Respond(respond);
                Console.ReadKey();
            }
        }
    }
}

This code is fairly straighforward in the sense that it kind of echoes the content of the Request.

If you now run both console applications, this is what will happen:

ENQ-ResponseQueueCreatedFirst a new queue “RequestClosureConsoleAppNamespace_MyRequest:RequestClosureConsoleAppAssembly” is created and the naming convention follows the one used for a PubSub exchange scenario i.e. there is no “id” in the name.

The other is the order in which the messages are sent and received:

Response log

2013-08-16 11:17:42.6424 INFO Received Send to Response Server 1 
2013-08-16 11:17:42.6414 INFO Received Send to Response Server 0 
2013-08-16 11:17:42.6424 INFO Received Send to Response Server 4 
2013-08-16 11:17:42.6424 INFO Received Send to Response Server 3 
2013-08-16 11:17:42.6424 INFO Received Send to Response Server 2

Request log

2013-08-16 11:17:42.7865 INFO Got response: Responding to Send to Response Server 2
2013-08-16 11:17:42.7985 INFO Got response: Responding to Send to Response Server 0
2013-08-16 11:17:42.7985 INFO Got response: Responding to Send to Response Server 3
2013-08-16 11:17:42.8155 INFO Got response: Responding to Send to Response Server 4
2013-08-16 11:17:42.8155 INFO Got response: Responding to Send to Response Server 1

This is really surprising because not only would it appear that the requests were sent in random order but the responses were processed and sent back in random order as well.

For completeness, here are the

MyRequest and MyResponse classes

namespace RequestClosureConsoleAppNamespace
{
    public class MyRequest|MyResponse    
    {
        public string Text { get; set; }
    }
}
Advertisements
Posted in .NET, ALT.NET, EasyNetQ, RabbitMQ

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: