我现在有一个失去信息的问题。这一错误很少发生,但经常发生,以致于令人讨厌。以下是这一问题的背景:
超时和接收消息是否可能同时发生?是否有更好的方法来处理服务停止检查以帮助避免此错误?
private void workerFunction()
{
logger.Info("Connecting to queue: " + Settings.Default.goldmine_service_queue);
MessageQueue q = new MessageQueue(Settings.Default.goldmine_service_queue);
q.Formatter = new ActiveXMessageFormatter();
while (serviceStarted)
{
Message currentMessage = null;
try
{
currentMessage = q.Peek(new TimeSpan(0,0,30));
}
catch (System.Messaging.MessageQueueException mqEx)
{
if (mqEx.ToString().Contains("Timeout for the requested operation has expired"))
{
logger.Info("Check for service stop request");
}
else
{
logger.Error("Exception while peeking into MSMQ: " + mqEx.ToString());
}
}
catch (Exception e)
{
logger.Error("Exception while peeking into MSMQ: " + e.ToString());
}
if (currentMessage != null)
{
logger.Info(currentMessage.Body.ToString());
try
{
ProcessMessage(currentMessage);
}
catch (Exception processMessageException)
{
logger.Error("Error in process message: " + processMessageException.ToString());
}
//Remove message from queue.
logger.Info("Message removed from queue.");
q.Receive();
//logPerformance(ref transCount, ref startTime);
}
}//end while
Thread.CurrentThread.Abort();
}发布于 2009-12-14 17:25:47
我不认为任何信息都应该在快速回顾的基础上被忽略,但是你的工作方式很奇怪,有很多比赛条件的空间。
为什么不直接接收该消息并将其传递给ProcessMessage (如果ProcessMessage失败,您将执行读取)。如果您需要处理多个接收者,那么在MSMQ事务中执行接收操作,以便消息对其他接收方不可用,但在事务提交之前不会从队列中删除。
另外,与其轮询队列,为什么不进行异步接收并让线程池处理完成(在这里您必须调用EndReceive)。这节省了一个线程,并且您不需要特殊情况服务关闭(关闭消息队列,然后调用MessageQueue.ClearConnectionCache();)。
另外,中止线程是一种非常糟糕的退出方式,只需从线程的启动函数返回即可。
发布于 2009-12-15 21:14:42
这里只是一些注释来说明MSMQ是如何工作的。
“我可以证明消息是插入到goldmine_service_queue中的,因为消息出现在消息日志中。
当原始消息从goldmine_service_queue中删除时,消息将进入日记队列。因此,您可以说消息已成功地传递到队列中,并成功地从队列中删除。
“我强烈怀疑我的问题可能与MessageQueue.Peek和超时行为有关。”
Peek不会将消息从队列中删除。只有“q.Receive()”才能做到这一点。在您的代码中,在正在查看的消息和接收到的消息之间没有明确的联系。"q.Receive();“只是说”从队列顶部接收消息“。在多线程环境中,您可以期望消息的读取不一致--有些消息可能会被多次查看和处理。您应该获得窥视消息的ID,并使用ReceiveByID,这样您只能接收窥视消息。
发布于 2009-12-14 17:30:13
我愿意将currentMessage = q.Peek(new TimeSpan(0,0,30));改为currentMessage = q.Receive();将解决您的问题。我一直使用MSMQ在完全相同的上下文中传递消息,但只使用peek (并期望出现超时异常)来确定它们的队列是否为空。对Receive的调用是阻塞的,尽管如此,请相应地进行计划。
编辑:也是为了捕捉异常--您可以通过比较错误代码来检查异常是否为超时异常。
mqe.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout其中mqe是您的消息队列异常。与字符串比较相比,您可能更喜欢这样做。
https://stackoverflow.com/questions/1901963
复制相似问题