通过ThreadLocal访问RabbitMQ IModel是否存在任何含义或陷阱



我创建了一个类,用于通过队列进行简单的文本消息传输

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);
}
}

初始化将类似

IConnection connection = ...
ThreadLocal channelThreadLocal = new ThreadLocal<IModel>(connection.CreateModel);
TextQueueTransmitter transmitter = new TextQueueTransmitter(() => channelThreadLocal.Value, "queue name");

之前我直接将IModel传递给发送器,但在读到这里的IModel不是线程安全的之后,我意识到如果我想使TextQueueTransmitter线程安全,我必须重新考虑它。

我的问题是,仅仅将IModel包装在ThreadLocal中是否有任何含义?例如,如果SendMessage()是在构建对象的线程之外的线程中调用的,那么QueueDeclareBasicPublish将在不同的线程上调用。这会引起什么问题吗?

更新:资源处置

正如Samuel在回答中指出的那样,有一个渠道处置问题我已经想到了,但我忘记写了。我计划做的是在程序终止时调用ThreadLocalDispose()希望这将调用底层IModels的Dispose()。尽管我必须进行验证,因为ThreadLocal文档没有指定它是否处理未删除的对象(如果它们实现IDisposable)。

这就造成了";悬挂的";连接,即具有不再运行的特定线程的连接。尽管我认为这不是一个严重的问题,因为所有TextQueueTransmitter实例都是长寿命对象,而且我不会过度创建线程。

我认为最大的问题是没有处理模型和泄漏资源。您需要控制它们的创建时间,并适当地处理它们。

最新更新