问题
I'm implementing a RabbitMQ client bus class in a .NET Framework web application.
The class is pretty basic like so:
public class RabbitConnection
{
private readonly IConnection conn;
public RabbitConnection() {
try {
var factory = new ConnectionFactory() {...}
this.conn = factory.CreateConnection();
}
catch {
...
}
}
public void Publish<T>(T @event) where T : class {
using (var channel = conn.CreateModel()) {
...
}
}
...
}
I have read that starting and closing connections with RabbitMQ is costly and you should keep a connection alive.
My question is, which is the best way to use this connection in the entire app? A singleton class? A static? Another way?
Thanks in advance!
回答1:
You have noted so:
I have read that starting and closing connections with RabbitMQ is costly and you should keep a connection alive.
RabbitMq uses AMQP protocol. It overcomes the difficulties which you have mentioned by using one and same TCP connection for all of your threads for performance. AMQP is able to do it by using channels. These channels is a virtual connection inside the “real” TCP connection, and it’s over the channel that you issue AMQP commands.
As each thread spins up, it creates a channel on the existing connection and gets its own private communication path to broker without any additional load on your operating system’s TCP stack. (For more details check my answer)
So, you are right that creating connection is costly and that's why you need one connection and multiple channels per thread which is created inside that connection.
My question is, which is the best way to use this connection in the entire app? A singleton class? A static? Another way?
It is better to use single instance of that class during the lifetime of application. Just use some DI framework for managing number of instances which has to be created during that lifetime.
And I prefer to add a method for initializing a connection. That method must be called while creating the instance of that class.
And for thread-safety you have to create new channel from that connection.
And don't forget to implement IDisposable interface and dispose connection as well.
So overall design will be so:
public interface IRabbitMqPublisher
{
void Init();
void Publish();
}
public class RabbitMqPublisher: IDisposable, IRabbitMqPublisher
{
private readonly IConnection conn;
public void Init();
public void Publish();
public void Dispose();
}
And from IOC container(f.e Autofac):
builder.RegisterType<IRabbitMqPublisher>()
.As<RabbitMqPublisher>()
.OnActivating(e => e.Instance.Init())
.SingleInstance();
By the way, Autofac (and I guess other containers as well) will automatically execute Dispose method at the end of each lifetime scope.
回答2:
To summarize the other answer and add some additional thoughts on this:
Create a class to wrap your connection to RabbitMQ. The class can then possibly deal with things like connection close, etc. and be the single point in your application to automatically reconnect.
Create a single instance of this class. I do not recommend the singleton pattern as it can lead to inflexibility in testing (see #3 below).
Use a dependency injection framework (.Net Core MVC has one built-in) to inject your connection wrapper class wherever you need it. This will then support unit testing much more easily than using a singleton.
来源:https://stackoverflow.com/questions/58753808/net-where-to-start-a-rabbitmq-client-connection-in-a-web-application