RabbitMQ exception case data - c#

I am new at RabbitMQ and doing first application. But I am confused a bit about exception stuations. For example I get a message from Queue. And an error occured while saving data to database. The data wil be lose. What is the solution of this problem?
var factory = new ConnectionFactory { HostName = "10.1.2.34" };
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "business.orders", durable: false, exclusive: false, autoDelete: false, arguments: null);
var data = channel.BasicGet(queue: "business.orders", noAck: true);
using (var stream = new MemoryStream(data.Body))
{
var order = (PlaceOrder)new BinaryFormatter().Deserialize(stream);
// Throw exception. ????
}
}
}

you have to use the manual ack:
var data = channel.BasicGet(queue: "business.orders", noAck: false);
insert into DB, if you don't have errors:
channel.BasicAck(result.DeliveryTag, false);
Please read here: https://www.rabbitmq.com/dotnet-api-guide.html
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;
...
Since noAck = false above, you must also call IModel.BasicAck to acknowledge that you have successfully received and processed the message:
...
// acknowledge receipt of the message
channel.BasicAck(result.DeliveryTag, false);
}
btw I suggest to read also: https://www.rabbitmq.com/dotnet-api-guide.html section:
Retrieving Messages By Subscription ("push API")
The basicGet is slower respect to the EventingBasicConsumer

Related

c# Rabbit MQ Unacked messages

I have an issue when trying to send ACK to remove messages from Rabbit queue.
Version of Rabbit MQ : 3.6.15. Version of RabbitClient 5.0.1
Here is my code:
var conn = Factory.CreateConnection();
var channel = conn.CreateModel();
//inside loop
var data = Get(conn, channel);
if (data == null)
return true;
if (data.MessageCount == 0)
return true;
var rabbitShortAd = JsonConvert.DeserializeObject<ShortAdRabbit>(Encoding.UTF8.GetString(Decompress(data.Body)));
//Process rabbitShortAd, save it in DB
//And if no error, send ack
SendAck(data, conn, channel);
return false;
//end loop
public static BasicGetResult Get(IConnection conn, IModel channel)
{
if (conn == null || !conn.IsOpen)
conn = Factory.CreateConnection();
if (channel == null || !channel.IsOpen)
channel = conn.CreateModel();
var queueName = "descriptions";
channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false);
return channel.BasicGet(queueName, false);
}
private static void SendAck(BasicGetResult data)
{
if (conn == null || !conn.IsOpen)
conn = Factory.CreateConnection();
if (channel == null || !channel.IsOpen)
channel = conn.CreateModel();
channel.BasicAck(data.DeliveryTag, false);
}
The first message processed is removed from the queue and then all others messages are stacking in the unacked column. My admin system just told me he updated the Rabbit MQ version to 3.6.15 and now I can't ACK my messages. Is there something wrong in the code ?
Found out the wait to make it work.
I have to instantiate the connection & the model inside the loop and then close each connection / model inside, too.
//inside the loop
var conn = Factory.CreateConnection();
var channel = conn.CreateModel();
try
{
var data = Get(conn, channel);
//Process
channel.BasicAck(data.DeliveryTag, false);
}
catch(Exception e)
{
//handle e
}
finally
{
conn?.Close();
channel?.Close();
}
//end of loop

Transfer data from one queue to another in RabbitMQ after specific time

Following is code of creating two RabbitMQ and trying to first add 3 list items in one queue and then removing data from one queue to another but its not working. Where I am missing here.
I took reference of following URL
https://medium.com/#kiennguyen88/rabbitmq-delay-retry-schedule-with-dead-letter-exchange-31fb25a440fc
private const string WORK_QUEUE = "LoanBeamQueue";
private const string WORK_EXCHANGE = "LoanBeamExchange"; // dead letter exchange
private const string RETRY_EXCHANGE = "DeadLetterExchange";
private const string WAIT_QUEUE = "DeadLetterQueue";
private const int RETRY_DELAY = 300000; // in ms
static void Main(string[] args)
{
try
{
// Declare the queue name
// Create a new connection factory for the queue
var factory = new ConnectionFactory();
// Because Rabbit is installed locally, we can run it on localhost
factory.HostName = ConnectionConstants.HostName;
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
// When reading from a persistent queue, you need to tell that to your consumer
var queueArgs = new Dictionary<string, object> {
{ "x-dead-letter-exchange", WORK_EXCHANGE },
{ "x-message-ttl", RETRY_DELAY }
};
const bool durable = true;
//channel.QueueDeclare(WORK_QUEUE, durable, false, false, null);
//channel.QueueDeclare(WAIT_QUEUE, durable, false, false, queueArgs);
#region Seperate
channel.ExchangeDeclare(WORK_EXCHANGE, "direct");
channel.QueueDeclare(WORK_QUEUE, true, false, false, null);
channel.QueueBind(WORK_QUEUE, WORK_EXCHANGE, string.Empty, null);
channel.ExchangeDeclare(RETRY_EXCHANGE, "direct");
channel.QueueDeclare(WAIT_QUEUE, true, false, false, queueArgs);
channel.QueueBind(WAIT_QUEUE, RETRY_EXCHANGE, string.Empty, null);
#endregion
#region NewAdded
List<string> lstDemoID2 = new List<string>();
lstDemoID2.Add("1");
lstDemoID2.Add("2");
lstDemoID2.Add("3");
foreach (var message in lstDemoID2)
{
var body = Encoding.UTF8.GetBytes(message);
//using default exchange
channel.BasicPublish(exchange: "", routingKey: "LoanBeamQueue", basicProperties: null, body: body);
Console.WriteLine("Sent ApplicationID {0}", message);
}
#endregion
// turn auto acknowledge off so we can do it manually. This is so we don't remove items from the queue until we're perfectly happy
//var consumer = new QueueingBasicConsumer(channel);
//const bool autoAck = false;
//channel.BasicConsume(WORK_QUEUE, true, consumer);
QueueingBasicConsumer consumer = new QueueingBasicConsumer(channel);
channel.BasicConsume(WORK_QUEUE, true, consumer);
}
}

RabbitMq sending message twice to the same consumer

I have implemented a rabbitmq messaging in my application. A very weird behaviour then.
My publisher is a webservice, while my consumer is a console application. After recieving the message I ack it immediately and span a new thread to process which take like 2 seconds to finish.
But the same message is sent with the previous delivery tag incremented by one. I am using topic based routing.
What would I be doing wrong?
Subscriber:
//Create the connection factory
var connectionFactory = new ConnectionFactory()
{
HostName = host,
UserName = userName,
Password = password
};
connectionFactory.RequestedHeartbeat = 10;
connectionFactory.RequestedConnectionTimeout = 30000;
connectionFactory.AutomaticRecoveryEnabled = true;
connectionFactory.NetworkRecoveryInterval = TimeSpan.FromSeconds(10);
//connection
var connection = connectionFactory.CreateConnection();
logger.Info($"Connected to RabbitMQ {host}");
connection.ConnectionShutdown += Connection_ConnectionShutdown;
var model = connection.CreateModel();
model.BasicQos(0, 1, false);
var consumer = new QueueingBasicConsumer(model);
model.BasicConsume(queueName, false, consumer);
while (true)
{
try
{
var deliveryArgs = consumer.Queue.Dequeue();
model.BasicAck(deliveryArgs.DeliveryTag, false);
var jsonString = Encoding.Default.GetString(deliveryArgs.Body);
var itemtoprocess = jsonString.FromJson < recieved message > ();
if (deliveryArgs.Redelivered)
{
model.BasicReject(deliveryArgs.DeliveryTag, false);
}
else
{
var task = Task.Factory.StartNew(() => {
//Do work here on different thread then this one
//Call the churner to process the message
//Some long running method here to process item recieve
});
Task.WaitAll(task);
}
}
catch (EndOfStreamException ex)
{
//log
}
}
Setup:
public void Init(string exchangeName, string queueName, string routingKey = "")
{
using (IConnection connection = connectionFactory.CreateConnection())
{
using (IModel channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchangeName, ExchangeType.Topic, true, false, null);
//Queue
var queue = channel.QueueDeclare(queueName, true, false, false, null);
channel.QueueBind(queue.QueueName, exchangeName, routingKey);
}
}
}

Message deleted automatically RabbitMQ

I have used RabbitMQ for storing messages. I noticed that messages are deleted when application restart.
I have producer and consumer in same application.
Please find producer and consumer as below. I have used durable queue as well as durable message.
So if there is only one consumer of queue and it's not consume currently then queue messages are deleted. Is it so ?
Producer:
public static void PublishMessage(RequestDto message, string queueName)
{
var factory = new ConnectionFactory() { HostName = Config.RabbitMqHostName, Port = Config.RabbitMqPortNumber };
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queueName, true, false, false, null);
var properties = channel.CreateBasicProperties();
properties.SetPersistent(true);
// properties.DeliveryMode = 2; I have used this too.
string serializesMessage = Utility.SerializeSoapObject(message);
var messageBytes = Encoding.UTF8.GetBytes(serializesMessage);
channel.BasicPublish("", queueName, properties , messageBytes);
Log.Info("Record added into queue : \nMessage: " + serializesMessage);
}
}
}
Consumer:
var factory = new ConnectionFactory() { HostName = Config.RabbitMqHostName, Port = Config.RabbitMqPortNumber };
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(Config.RabbitMqQueueName, true, false, false, null);
var consumer = new QueueingBasicConsumer(channel);
channel.BasicConsume(Config.RabbitMqQueueName, true, consumer);
while (DoProcessMessage())
{
try
{
List<RequestDto> messages = GetMessagesInBatch(consumer);
if (messages.Count > 0)
{
ProcessMessageInParallel(messages);
}
else
{
Producer.FillRequestMessages();
}
}
catch (Exception exception)
{
Log.Error("StartConsumer - Failed to process message from RabbitMq Error: " + exception.Message, exception);
}
}
}
}
}
catch (Exception exception)
{
Log.Error(exception.Message, exception);
}
private bool DoProcessMessage()
{
return Config.MaxRequestPerDayCount > 1000;
}
If anyone can help.
You seem to be passing noAck = true to the basicConsume function:
https://www.rabbitmq.com/releases/rabbitmq-java-client/v1.7.0/rabbitmq-java-client-javadoc-1.7.0/com/rabbitmq/client/Channel.html#basicConsume(java.lang.String, boolean, com.rabbitmq.client.Consumer)
In no ack mode, RabbitMQ will send the messages to the consumer and immediately delete it from the queue.

RabbitMq Implementation Practically

I am working on rabbitmq and I am confused with some points Like.
I have just implemented a sample from internet which creates a queue and then it fetch
the message from that queue thereby showing it on the webpage.
Now my problem is::
Suppose My server has RabbitmQ installed and multiple users are accessing this website where I
have implemented the rabbitmq.Now, first user sends a message but to whome it will send this message?
To all the users who will open the page because the code will be common for sent message and the name
of the queue will also be same.
Suppose, first user send one message="Hello" on the queue "Queue1"
now, one other user sends another message="Hello World" on the same queue
and one more user sends a message="Hello Worl World" on the same queue.
Now nth user clicks on receive message then which message will be shown to him?
first ,second or third one?
It means we will always have a single queue for my application?
Can somebody please guide me. I am pretty much confused...
Below I am pasting the code sample I will be using for my website
//For sending the messge
protected void btnSendMail_Click(object sender, EventArgs e)
{
try
{
var factory = new ConnectionFactory();
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
// ConnectionFactory factory = new ConnectionFactory() { HostName = "localhost" };
// // factory.UserName = txtUserEmail.Text.ToString();
//// factory.Password = "password";
// factory.VirtualHost = "/";
// factory.Protocol = Protocols.FromEnvironment();
// factory.HostName = "localhost";
// factory.Port = AmqpTcpEndpoint.UseDefaultPort;
// IConnection conn = factory.CreateConnection();
// using (var channel = conn.CreateModel())
// {
// channel.QueueDeclare("hello", false, false, false, null);
// string message = "Hello World!";
// var body = Encoding.UTF8.GetBytes(txtUserEmail.Text.ToString());
// channel.BasicPublish("", "hello", null, body);
// conn.Close();
// }
//Sending Message
channel.QueueDeclare("hello1", false, false, false, null);
string message = txtUserEmail.Text.ToString();
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("", "hello1", null, body);
//Console.WriteLine(" [x] Sent {0}", message);
//Console.ReadLine();
Label1.Text = Encoding.Default.GetString(body);
}
}
}
catch
{
}
}
//For receiving the message.
protected void btnReceive_Click(object sender, EventArgs e)
{
try
{
//var factory = new ConnectionFactory() { HostName = "localhost" };
//using (var connection = factory.CreateConnection())
//{
// using (var channel = connection.CreateModel())
// {
// channel.QueueDeclare("hello", false, false, false, null);
// BasicGetResult result = channel.BasicGet("hello", false);
// var consumer = new QueueingBasicConsumer(channel);
// channel.BasicConsume("hello", true, 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);
// Label1.Text = message.ToString();
// }
// }
//}
var factory = new ConnectionFactory();
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
bool noAck = false;
BasicGetResult result = channel.BasicGet("hello1", noAck);
if (result == null)
{
}
else
{
IBasicProperties props = result.BasicProperties;
byte[] Body = result.Body;
Label1.Text = Encoding.Default.GetString(Body);
}
}
}
}
catch
{
}
}
If you are creating a messaging system using RabbitMQ you should probably publish your messages to an exchange and then attach a queue to the exchange for each user of the site. Then have the exchange route the messages to the right user/users queue.
You need a better understanding of messaging patterns associated with the use of RabbitMQ
These tutorials would be most relevant
Publish/Subscribe
http://www.rabbitmq.com/tutorials/tutorial-three-python.html
Routing
http://www.rabbitmq.com/tutorials/tutorial-four-python.html
The tutorials are also available in c# if you need it.

Categories