I am using sample code to implement Publish/Subscribe using "fanout" exchange type. But as in below code subscriber is not displaying 'Hello Word' message which is published.
Publisher.cs
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchange: "logs", type: "fanout");
var message = GetMessage(args);
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "logs",
routingKey: "",
basicProperties: null,
body: body);
Console.WriteLine(" [x] Sent {0}", message);
}
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
private static string GetMessage(string[] args)
{
return ((args.Length > 0)
? string.Join(" ", args)
: "info: Hello World!");
}
Subscriber.cs
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchange: "logs", type: "fanout");
var queueName = channel.QueueDeclare().QueueName;
channel.QueueBind(queue: queueName,
exchange: "logs",
routingKey: "");
Console.WriteLine(" [*] Waiting for logs.");
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine(" [x] {0}", message);
};
channel.BasicConsume(queue: queueName,
noAck: true,
consumer: consumer);
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
Code Ref: https://www.rabbitmq.com/tutorials/tutorial-three-dotnet.html
As you figured out it actually works, you just need to start the subscriber first. Why? The answer is also on the link you provided. I'll quote one part here:
But that's not the case for our logger. We want to hear about all log
messages, not just a subset of them. We're also interested only in
currently flowing messages not in the old ones. To solve that we need
two things.
Firstly, whenever we connect to Rabbit we need a fresh, empty queue.
To do this we could create a queue with a random name, or, even better
- let the server choose a random queue name for us.
Secondly, once we disconnect the consumer the queue should be
automatically deleted.
This basically means that the queue is created only when you start the subscriber, and only at that point, the exchange has a queue to actually put the message in. Since you fist start the publisher, there is no queue for the message to end up in.
Related
Looking at the example code from Rabbit MQ's site for a consumer...
var factory = new ConnectionFactory() { HostName = "localhost" };
using(var connection = factory.CreateConnection())
using(var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "hello",
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine(" [x] Received {0}", message);
};
channel.BasicConsume(queue: "hello",
autoAck: true,
consumer: consumer);
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
It initially looked like the messages were coming off the queue 1 by 1 in order and handled consecutively by the code inside the Received section.
However the result I am now seeing suggests that they are probably coming off 1 by 1 in order, but being handle concurrently, is this correct?
Regards
Tom
Using RabbitMQ it is possible to control how many messages that should be processed concurrent by calling:
channel.BasicQos(0, <MaxConcurrentConsumerThreads>, false);
So if chronology is important calling channel.BasicQos(0, 1, false); ensures only 1 message is processed at a time.
At The moment im learning how to work with the RabbitMQ.
Sending works. But Recieving doesn't work. This is my code:
var factory = new ConnectionFactory() { HostName = hostName };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: queueName,
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("Recieved: {0}", message);
};
consumer.Shutdown += (o, e) =>
{
Console.WriteLine("Error with RabbitMQ: {0}", e.Cause);
createConnection(hostName, queueName);
};
channel.BasicConsume(queueName, true, consumer);
}
This is copied from the Tutorial. If I start the Application, consumer.Shutdown is directly called and I get:
{AMQP close-reason, initiated by Application, code=200, text="Goodbye", classId=0, methodId=0, cause=}
Can anyone help me?
channel.BasicConsume is non-blocking call, which means it will return immediately. What happens next in your example is your channel and connection are getting disposed (because of using statement), and so you see immediate shutdown. In the example you copied this code from, there is Console.ReadLine statement right after channel.BasicConsume. This prevents channel and connection from disposing until user press key in console.
Is there a good example (C#) of how to do the direct reply-to in RabbitMQ? What I want to do is for X Producers to post a message ("I've got some work for somebody") and I want one of X Consumers to pick it up, do the work and send the response back. Not a basic Ack, but some data, the result of the calculation. Of course, the response has to go back to the right producer.
Producer:
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "hello",
durable: true,
exclusive: false,
autoDelete: false,
arguments: null);
string message = "Hello World!";
var body = Encoding.UTF8.GetBytes(message);
var properties = channel.CreateBasicProperties();
properties.Persistent = true;
channel.BasicPublish(exchange: "",
routingKey: "hello",
basicProperties: properties,
body: body);
Console.WriteLine(" [x] Sent {0}", message);
}
}
Consumer:
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "hello",
durable: true,
exclusive: false,
autoDelete: false,
arguments: null);
channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine(" [x] Received {0}", message);
channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
};
channel.BasicConsume(queue: "hello",
noAck: false,
consumer: consumer);
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
It's not very clear from the minimal docs on how to set up both sides. I know somebody has to do something with the "amq.rabbitmq.reply-to" queue, but its not clear which side and what they have to do with it.
Have you seen the tutorials on the rabbitmq website? http://www.rabbitmq.com/tutorials/tutorial-six-dotnet.html
You would set up your code the same way as the RPC example, above, with only a few minor differences (noted in the docs you've referenced: https://www.rabbitmq.com/direct-reply-to.html).
When publishing a message from the original message producer, set the "replyTo" to amq.rabbitmq.reply-to
Have the original message producer also be a message consumer, consuming from the amq.rabbitmq.reply-to queue
When the code that handles the original request is done processing, you will publish a message from that worker, through the default (empty, no-name, "") exchange, with the routing key also set to amq.rabbitmq.reply-to
So:
client begins consuming messages from amq.rabbitmq.reply-to queue
client sends request for work, with amq.rabbitmq.reply-to as the replyTo property
worker picks up message, does work, publishes a response through the "" exchange, using amq.rabbitmq.reply-to as the routing key
that should be about it
My problem is, that my code is running unpredictable. First here is my code:
var receivedmsg = "empty_string";
channel.QueueDeclare(queue: "rabbittestqueue",
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
String message = Encoding.UTF8.GetString(body);
Console.WriteLine(" [x] Received message1: {0}", message);
receivedmsg = message;
};
channel.BasicConsume(queue: "rabbittestqueue",
noAck: true,
consumer: consumer);
Console.WriteLine(" [x] Received message2: {0}", receivedmsg);
return receivedmsg;
The problem is, that [x] Received message2 run sometimes first, then [x] Received message1
The code that I'm using is from here:
https://www.rabbitmq.com/tutorials/tutorial-one-dotnet.html
Why does this happening?
Because you wrote
Console.WriteLine(" [x] Received message2: {0}", receivedmsg);
in the "main thread" and
Console.WriteLine(" [x] Received message1: {0}", message);
in the event that happens when the message is received. The console output order will be like that in 99.99% of the time.
You are using a "push" consumer method to pull messages.
If you want to "pull" messages from the queue, use the "pull API", which is called BasicGet instead of BasicConsume.
Having a predictable and syncronous "push API" is self-contradictory. The "push" will happen when it happens... not when you want it to happen in your application. That's the point of a "push" API.
You can find a general API description here, especially the headings Fetching Individual Messages ("pull API") and Retrieving Messages By Subscription ("push API").
I am beginner to RabbitMQ integration. I was doing some experiment with RabbitMq and making it as task runner.
For eg:
Let say I have a class Tasks, which has a method called Foo()
public static string Foo(string test, int id)
{
return "Admin" + test + id.ToString();
}
I have another class called Producer, which is declaring Queue for RabbitMQ.
using (var conn = factory.CreateConnection())
{
using (var channel = conn.CreateModel())
{
channel.QueueDeclare(queue: "KKQueue", durable: false, exclusive: false, autoDelete: false, arguments: null);
var message = "Hello World";
channel.BasicPublish(exchange: string.Empty, routingKey: "KKQueue", basicProperties: null, body: Encoding.UTF8.GetBytes(message ));
Console.WriteLine(" [x] Sent {0}", message);
}
Console.WriteLine(" Press [enter] to exit.");
}
Here we have to pass string as message to consumer.
Consumer class code will consume this queue message
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "KKQueue", durable: false, exclusive: false, autoDelete: false, arguments: null);
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var message = Encoding.UTF8.GetString(ea.Body);
Console.WriteLine(" [x] Received {0}", message);
};
channel.BasicConsume(queue: "KKQueue", noAck: true, consumer: consumer);
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
which is accepting string message. Is there a way, by which I can pass put my function call to Producer or Rabbit MQ Queue and let Consumee execute those function calls which are in queue.
I tried by serializing/deserializing the object and then using reflection to invoke the method in consumer code..I am looking for some alternate solution to it by using delegate or something. Any help will be greatly appreciated.
No, you can't. You need to "ship" all the assembly code with the message, which is definitively a very bad idea.
You should add you task code library to you consumer app and then use the message to govern the task execution, but without sending the executable code with it.
I personally use MassTransit for this kind of producer/consumer scenario; for example you can have multiple consumers, one for each task, and you can activate the right consumer simply sending a different type of message through RMQ.