I have a created a class to facilitate simple text message transmission over a queue
public class TextQueueTransmitter
{
private Func<IModel> channelProvider;
private IBasicProperties props;
private string queue;
public TextQueueTransmitter(Func<IModel> channelProvider, string queue)
{
this.queue = queue;
this.channelProvider = channelProvider;
//will be called once in a thread
this.channelProvider().QueueDeclare(queue: queue,
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
props = this.channelProvider().CreateBasicProperties();
}
public void SendMessage(string message)
{
var body = Encoding.UTF8.GetBytes(message);
props.DeliveryMode = 1;
//will be called multiple times not necessarily in the same thread
channelProvider().BasicPublish(exchange: "",
routingKey: queue,
basicProperties: null,
body: body);
}
}
Initialization will be like
IConnection connection = ...
ThreadLocal channelThreadLocal = new ThreadLocal<IModel>(connection.CreateModel);
TextQueueTransmitter transmitter = new TextQueueTransmitter(() => channelThreadLocal.Value, "queue name");
previously I was directly passing IModel to the transmitter but after reading here that IModel is not thread safe, I realized I had to rethink it if I wanted to make TextQueueTransmitter thread safe.
My question is are there any implications of just wrapping IModel in ThreadLocal? For example if SendMessage() is called in a thread other than the one that constructed the object, then QueueDeclare
and BasicPublish
will be called on different threads. Would that cause any problems?
Update: Resource disposal
As Samuel pointed out in his answer, there is the channel disposal issue that I have thought of but I forgot to write about. What I was planing to do, is call Dispose()
of ThreadLocal
on program's termination, hoping that this will call Dispose() of the underlying IModel
s. Though I will have to verify since ThreadLocal documentation does not specify if it disposes the undelying objects (should they implement IDisposable).
This imposes the danger of "dangling" connections i.e. having connections for a specific thread no longer running. Though I don't consider it grave problem since all TextQueueTransmitter
instances are intended to be long lived objects and I don't create threads excessively.