RabbitMQ .NET Client and connection timeouts - rabbitmq

I'm trying to test the AutomaticRecoveryEnabled property of the RabbitMQ ConnectionFactory. I'm connecting to a RabbitMQ instance on a local VM and on the client I'm publishing messages in a loop. The problem is if I intentionally break the connection, the client just waits forever and doesn't time out. How do I set the time out value? RequestedConnectionTimeout doesn't appear to have any effect.
I'm using the RabbitMQ client 3.5.4
Rudimentary publish loop:
// Client is a wrapper around the RabbitMQ client
for (var i = 0; i < 1000; ++i)
{
// Publish sequentially numbered messages
client.Publish("routingkey", GetContent(i)));
Thread.Sleep(100);
}
The Publish method inside the wrapper:
public bool Publish(string routingKey, byte[] body)
{
try
{
using (var channel = _connection.CreateModel())
{
var basicProps = new BasicProperties
{
Persistent = true,
};
channel.ExchangeDeclare(_exchange, _exchangeType);
channel.BasicPublish(_exchange, routingKey, basicProps, body);
return true;
}
}
catch (Exception e)
{
_logger.Log(e);
}
return false;
}
The connection and connection factory:
_connectionFactory = new ConnectionFactory
{
UserName = _userName,
Password = _password,
HostName = _hostName,
Port = _port,
Protocol = Protocols.DefaultProtocol,
VirtualHost = _virtualHost,
// Doesn't seem to have any effect on broken connections
RequestedConnectionTimeout = 2000,
// The behaviour appears to be the same with or without these included
// AutomaticRecoveryEnabled = true,
// NetworkRecoveryInterval = TimeSpan.FromSeconds(10),
};
_connection = _connectionFactory.CreateConnection();

It appears this is a bug in version 3.5.4. Version 3.6.3 does not wait indefinitely.

Related

ASP.NET CORE combined with RabbitMq message queue

I am using asp.net core to create a project, I want to combine rabbitmq to realize the sending and receiving of message queue.I installed rabbitmq using docker and it runs successfully.But the queue I registered in the project is not displayed on the RabbitMq management interface.
ConnectionFactory factory = new ConnectionFactory
{
UserName = "guest",
Password = "guest",
HostName = "*******"
};
var connection = factory.CreateConnection();
var channel = connection.CreateModel();
channel.QueueDeclare("test", false, false, false, null);
Console.WriteLine("\nRabbitMQ enter exit to exit!");
string input;
do
{
input = Console.ReadLine();
var sendBytes = Encoding.UTF8.GetBytes(input);
channel.BasicPublish("", "test", null, sendBytes);
} while (input.Trim().ToLower()!="exit");
channel.Close();
connection.Close();
The above is my message production code.But there is no display on my RabbitMq dashboard.
enter image description here
You did not specify the port number to connect to and the VirtualHost to connect to, I am not sure if you are caused by this. Do you have a specific error? Or your project can run normally. I have written a demo for sending messages here, you can refer to it, it may be useful to you.
class Program
{
static void Main(string[] args)
{
try
{
var factory = new ConnectionFactory();
factory.VirtualHost = "/";
factory.HostName = "localhost";
factory.Port = 5672;
factory.UserName = "guest";//Default username guest
factory.Password = "guest";//Default password guest
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "hello",
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
string message = "Hello World!";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "",
routingKey: "hello",
basicProperties: null,
body: body);
Console.WriteLine(" [x] Sent {0}", message);
}
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
catch (Exception ex)
{
Console.Write(string.Format("RabbitMQ connection error :{0}\n", ex.ToString()));
}
}
}
Refer to the official document example:
https://www.rabbitmq.com/tutorials/tutorial-one-dotnet.html
If you run this code and get this error:
Check if your corresponding virtual hosts match, I set "/" here, if you are not, please add your hosts here:
Result:
console:
rabbitmq:

Getting RabbitMq to behave as I want (dead letter and re-queue on errors)

I have a simple rabbit set up that is currently doing what I want...
It publishes messages based on the type of message. Each type gets its own queue.
When messages are published they sit on the queue even if there is no consumer to consume them (sit there forever if no consumer arrives).
When a consumer is there (there is only one!) it eats the messages.
If for some reason it cannot handle a message (eg it gets a sub message before the parent has arrived) it nacks the message back onto the queue.
If it sees the same message six times it nacks the message.
This all works, but currently after six attempts it drops the message.
What I would like is for the message to pass to a 'dead letter queue' and after some time (say 5 mins) re-queue that message at the end of the particular queue it came from.
I am definitely cargo cult programing and I don't quite understand all the exchange/queue/binding/routing keys and other arcania involved... hand holding is appreciated!
public void PublishEntity<T>(T message) where T : class, ISendable
{
logger.Info($"publishing {message.UniqueId}");
var factory = new ConnectionFactory
{
HostName = appSettings.RabbitHostName,
UserName = appSettings.RabbitUsername,
Password = appSettings.RabbitPassword
};
try
{
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
Console.WriteLine($"Setting up queues for: {typeof(T).Name}");
channel.QueueDeclare($"App_{typeof(T).Name}",
true,
false,
false,
null);
var json = JsonConvert.SerializeObject(message);
var body = Encoding.UTF8.GetBytes(json);
channel.TxSelect();
var properties = channel.CreateBasicProperties();
properties.Persistent = true;
properties.Headers = new Dictionary<string, object>
{
{ "Id", Guid.NewGuid().ToString() }
};
channel.BasicPublish("",
$"App_{typeof(T).Name}",
properties,
body);
Data.MarkAsSent(message);
channel.TxCommit();
}
}
}
ISendable just make sure the message has some properties used in Data.MarkAsSent(message); to mark in a database where we have got too.
The receiver has a similar lump of code to handle each type. As I say this is working.
What do I need to do to add the dead letter queue things?
My attempt like so created the dead letter queues, but nothing ever moves to them.
public void PublishEntity<T>(T message) where T : class, ISendable
{
logger.Info($"publishing {message.UniqueId}");
var factory = new ConnectionFactory
{
HostName = appSettings.RabbitHostName,
UserName = appSettings.RabbitUsername,
Password = appSettings.RabbitPassword
};
try
{
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
Console.WriteLine($"Setting up queues for: {typeof(T).Name}");
channel.ExchangeDeclare("App.Dead.Letter", "direct", true);
var args = new Dictionary<string, object>
{
{ "x-dead-letter-exchange", "App.Dead.Letter" },
{
"x-dead-letter-routing-key", $"DLQ.App_{typeof(T).Name}"
}
};
channel.QueueDeclare($"App_{typeof(T).Name}",
true,
false,
false,
args);
channel.QueueDeclare($"DLQ.App_{typeof(T).Name}",
true,
false,
false,
null);
var json = JsonConvert.SerializeObject(message);
var body = Encoding.UTF8.GetBytes(json);
channel.TxSelect();
var properties = channel.CreateBasicProperties();
properties.Persistent = true;
properties.Headers = new Dictionary<string, object>
{
{ "Id", Guid.NewGuid().ToString() }
};
channel.BasicPublish("",
$"App_{typeof(T).Name}",
properties,
body);
Data.MarkAsSent(message);
channel.TxCommit();
}
}
}
In my reciever I have this magic
catch (Exception ex)
{
var attemptsToHandle = MarkFailedToHandleMessage(logId, ex);
if (attemptsToHandle > 5)
{
//If we have seen this message many times then don't re-que.
channel.BasicNack(ea.DeliveryTag, false, false);
return;
}
// re-que so we can re-try later.
channel.BasicNack(ea.DeliveryTag, false, true);
return;
}
Phew... lot of code. Thanks if you have made it this far....
I am asking what are the glaring issues in my code to make things fall to the dead letter queue.
and what extra do I need to add so that things in the dlq will bounce back to the main queue after some time.
Additionally this sets up a dlq for each types queue... is this required or should there be a single queue to hold the errored messages?
So I think I got this working as I intend. Hard to test all this stuff though!
public void PublishEntity<T>(T message) where T : class, ISendable
{
logger.Info($"publishing {message.UniqueId}");
var factory = new ConnectionFactory
{
HostName = appSettings.RabbitHostName,
UserName = appSettings.RabbitUsername,
Password = appSettings.RabbitPassword
};
try
{
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
Console.WriteLine($"Setting up queues for: {typeof(T).Name}");
// Declair dead letter queue for this type
channel.ExchangeDeclare("App.Dead.Letter", "direct", true);
var queueArgs = new Dictionary<string, object>
{
{ "x-dead-letter-exchange", "App" },
{
"x-dead-letter-routing-key", $"App_{typeof(T).Name}"
}
,{ "x-message-ttl", 30000 }
};
channel.QueueDeclare($"DLQ.App_{typeof(T).Name}",
true,
false,
false,
queueArgs);
channel.QueueBind($"DLQ.App_{typeof(T).Name}", "App.Dead.Letter", $"DLQ.App_{typeof(T).Name}", null);
// declair queue for this type
channel.ExchangeDeclare("App", "direct", true);
var args = new Dictionary<string, object>
{
{ "x-dead-letter-exchange", "App.Dead.Letter" },
{
"x-dead-letter-routing-key", $"DLQ.App_{typeof(T).Name}"
}
};
channel.QueueDeclare($"App_{typeof(T).Name}",
true,
false,
false,
args);
channel.QueueBind($"App_{typeof(T).Name}", "App", $"App_{typeof(T).Name}", null);
I added and exchange for my main queues to live in and actually bound the queues to the exchanges. I still don't know why I need to do this as it was working without this extra complexity.. I guess some magic was hiding it from me before?

How to specify a password for Redis and his sentinels?

We going to use ServiceStack.RedisClient, but I was not able figure out how to define a password for sentinels and masters.
I've tried pwd#ipv4:port but no result.
Our code is:
var sentinelHosts = new[] { "node1:26379", "node2:26379", "node3:26379" };
var sentinel = new RedisSentinel(sentinelHosts, "mymaster");
var manager = sentinel.Start();
while (true)
{
using (var client = manager.GetClient())
{
try
{
Console.WriteLine(client.IncrementValue("MyTestKey"));
}
catch (RedisException ex)
{
Console.WriteLine($"Error {ex.Message}");
}
}
Thread.Sleep(1000);
}
You can specify to use passwords for connecting to masters / slaves with an Custom Redis Connection String, e.g:
sentinel.HostFilter = host => "pwd#{0}".Fmt(host);

Need help in creating RabbitMQ consumer as windows service?

This code works fine with console application but it doesnt work with Windows service application.
//code to receive message from queue
public void ReceiveMessage()
{
const string EXCHANGE_NAME = "EXCHANGE3";
ConnectionFactory factory = new ConnectionFactory();
//Rabbit MQ connection
using (IConnection connection = factory.CreateConnection())
{
using (IModel channel = connection.CreateModel())
{
channel.QueueDeclare("task_queue", true, false, false, null);
channel.BasicQos(0, 1, false);
var consumer = new QueueingBasicConsumer(channel);
channel.BasicConsume("task_queue", false, consumer);
//Waiting in loop to get message
while (true)
{
var ea =
(BasicDeliverEventArgs)consumer.Queue.Dequeue();
Object message = Desserialize(ea.Body);
//Acknowledge one or more delivered message
channel.BasicAck(ea.DeliveryTag, false);
}
}
}
}

Send message has been delivering successfully, But when i'm trying to get messages from agent no messages be presented in agent

I'm new to JMS+OPenMq + Glassfish , please give me up by make successful send message and receive messages....
I have created two different servlet programs and i have deployed in galssfish server....Here i'm sending message successfully , but consumer has not able to consuming messages ......
producer :
Properties p = new Properties();
p.put("java.naming.factory.initial","com.sun.enterprise.naming.SerialInitContextFactory");
p.put("java.naming.factory.url.pkgs","com.sun.enterprise.naming");
p.put("java.naming.provider.url", "iiop://localhost:3700");
InitialContext jndiContext = new InitialContext(p);
TopicConnectionFactory connectionFactory = (TopicConnectionFactory) jndiContext.lookup("jms/HQTapicConnectionFactory");
Topic topic = (Topic) jndiContext.lookup("jms/HqDestTopic");
System.out.println(topic.getTopicName());
TopicConnection connection = (TopicConnection) connectionFactory.createTopicConnection();
System.out.println(connection.toString());
TopicSession session = connection.createTopicSession(true, Session.AUTO_ACKNOWLEDGE); //createSession(false, Session.AUTO_ACKNOWLEDGE);
TopicPublisher publisher = session.createPublisher(topic);
ObjectMessage message = session.createObjectMessage();
ArrayList<Employee> employeeList= new ArrayList<Employee>();
Employee employee = null;
for (int i = 0; i < 5; i++) {
employee = new Employee();
employee.setEmpid((100+i));
employee.setName("devid"+i);
employeeList.add(employee);
}
System.out.println(employeeList.size());
message.setObject(employeeList);
publisher.send(message);
Consumer:
public void onMessage(Message message){
ObjectMessage objectMessage= (ObjectMessage) message;
try{
System.out.println("Received the following message: ");
Object object = objectMessage.getObject();
if(object instanceof ArrayList){
ArrayList arrayList = (ArrayList)object;
for (int i = 0; i < arrayList.size(); i++) {
Object object1 = arrayList.get(i);
if(object1 instanceof Employee){
Employee employee = (Employee)object1;
System.out.println(employee.getEmpid());
System.out.println(employee.getName());
System.out.println();
}
}
}
}
catch (JMSException e)
{
e.printStackTrace();
}
}
I'm not able to receiving messages ,
Please help me to proper configure for broker in glassfish server.
,...appreciate for your replay
If your consumer is in a servlet, it will only catch the messages which are sent in the same moment of time (quite unlikely) - you are using topics which do not buffer by default.
Either use queues (instead of topics) or write a stand-alone program which is permanently running (and thus listening/eceiving). Normally topic listeners do not make much sense in a servlet.