我在一个名为“MessageQueueReceive”的类中有这个。
public MessageQueueTransaction BlockingReceive(out Message message)
{
MessageQueueTransaction tran = null;
message = null;
tran = new MessageQueueTransaction();
tran.Begin();
try
{
message = Queue.Receive(new TimeSpan(0, 0, 5), tran);
}
catch (MessageQueueException ex)
{
// If the exception was a timeout, then just continue
// otherwise re-raise it.
if (ex.MessageQueueErrorCode != MessageQueueErrorCode.IOTimeout)
throw ex;
}
return tran;
}
然后我的处理循环有: -
while (!Abort)
{
try
{
tran = this.Queue.BlockingReceive(out msg);
if (msg != null)
{
// Process message here
if (tran != null)
tran.Commit();
}
}
catch (Exception ex)
{
if (tran != null)
tran.Abort();
}
}
控制面板工具显示我正在使用的消息队列是事务性的。日记帐队列未启用。
此代码创建队列: -
private static MessageQueue CreateMessageQueue(string queueName, bool transactional = false)
{
MessageQueue messageQueue = MessageQueue.Create(queueName, transactional);
messageQueue.SetPermissions("Administrators", MessageQueueAccessRights.FullControl,
AccessControlEntryType.Allow);
return messageQueue;
}
调用此参数时,事务参数设置为“true”。
我发现当在处理消息期间发生异常时,会调用tran.Abort,但此时我希望将消息返回到队列中。但是,这种情况并没有发生,消息也会丢失。
我错过了一些明显的东西吗?谁能看到我做错了什么?
答案 0 :(得分:5)
感谢所有评论。我确实重新组织了我的代码,正如Russell McClure建议的那样,我试图创建简单的测试用例,但无法重现问题。
最后,问题完全不在我看的地方(这种情况多久发生一次?)。
在我的管道中,我有一个重复的邮件检查器。我的系统处理的“消息”来自WAN上的远程设备,有时候线路上的消息也是重复的。
当从MSMQ中提取消息时,它将通过重复检查程序传递给数据库编写器。如果数据库写程序失败,则检查的重复项不会从其表中删除哈希。当进程再次尝试循环时,它将从队列agan获取相同的消息,因为MSMQ事务已在数据库写入程序失败时回滚。但是,在第二次尝试时,重复检查器会发现它之前已经看到过该消息,并以静默方式吞下它。
修复方法是让重复检查器发现来自链中下一个链接的异常,并回滚它所做的任何事情。
答案 1 :(得分:1)
您的队列需要创建为事务性队列才能获得所需的内容。
编辑:
好吧,如果您的队列是事务性的,那么这表明您错误处理了您的事务,尽管我无法具体了解它是如何发生的。我会更改 BlockingReceive 方法以返回消息。我会将 MessageQueueTransaction 的创建移动到外部方法。如果您使用相同的方法调用Begin,Commit和Abort方法,则代码将更易于维护。