首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否有可能在超时的情况下使用MSMQ MessageQueue.Peek丢失消息?

是否有可能在超时的情况下使用MSMQ MessageQueue.Peek丢失消息?
EN

Stack Overflow用户
提问于 2009-12-14 16:35:06
回答 3查看 8.5K关注 0票数 6

我现在有一个失去信息的问题。这一错误很少发生,但经常发生,以致于令人讨厌。以下是这一问题的背景:

  • I打开了goldmine_service_queue上的消息日志,这是Windows2003Server上的MSMQ。
  • I可以证明消息被插入到goldmine_service_queue中,因为消息出现在消息日志中。此信息提供了关于消息disappeared.
  • The日志记录函数何时使用http://logging.apache.org/log4net/index.html
  • The日志时不显示错误的计时信息。
  • --工作函数(如下图所示)在http://logging.apache.org/log4net/index.html
  • The服务的线程内执行。它负责查看队列中的消息(工作项)并处理它们。从日志中的
  • ,我强烈怀疑我的问题可能与MessageQueue.Peek和超时行为有关。

超时和接收消息是否可能同时发生?是否有更好的方法来处理服务停止检查以帮助避免此错误?

代码语言:javascript
复制
        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();

    }
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-12-14 17:25:47

我不认为任何信息都应该在快速回顾的基础上被忽略,但是你的工作方式很奇怪,有很多比赛条件的空间。

为什么不直接接收该消息并将其传递给ProcessMessage (如果ProcessMessage失败,您将执行读取)。如果您需要处理多个接收者,那么在MSMQ事务中执行接收操作,以便消息对其他接收方不可用,但在事务提交之前不会从队列中删除。

另外,与其轮询队列,为什么不进行异步接收并让线程池处理完成(在这里您必须调用EndReceive)。这节省了一个线程,并且您不需要特殊情况服务关闭(关闭消息队列,然后调用MessageQueue.ClearConnectionCache();)。

另外,中止线程是一种非常糟糕的退出方式,只需从线程的启动函数返回即可。

票数 5
EN

Stack Overflow用户

发布于 2009-12-15 21:14:42

这里只是一些注释来说明MSMQ是如何工作的。

“我可以证明消息是插入到goldmine_service_queue中的,因为消息出现在消息日志中。

当原始消息从goldmine_service_queue中删除时,消息将进入日记队列。因此,您可以说消息已成功地传递到队列中,并成功地从队列中删除。

“我强烈怀疑我的问题可能与MessageQueue.Peek和超时行为有关。”

Peek不会将消息从队列中删除。只有“q.Receive()”才能做到这一点。在您的代码中,在正在查看的消息和接收到的消息之间没有明确的联系。"q.Receive();“只是说”从队列顶部接收消息“。在多线程环境中,您可以期望消息的读取不一致--有些消息可能会被多次查看和处理。您应该获得窥视消息的ID,并使用ReceiveByID,这样您只能接收窥视消息。

票数 3
EN

Stack Overflow用户

发布于 2009-12-14 17:30:13

我愿意将currentMessage = q.Peek(new TimeSpan(0,0,30));改为currentMessage = q.Receive();将解决您的问题。我一直使用MSMQ在完全相同的上下文中传递消息,但只使用peek (并期望出现超时异常)来确定它们的队列是否为空。对Receive的调用是阻塞的,尽管如此,请相应地进行计划。

编辑:也是为了捕捉异常--您可以通过比较错误代码来检查异常是否为超时异常。

代码语言:javascript
复制
mqe.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout

其中mqe是您的消息队列异常。与字符串比较相比,您可能更喜欢这样做。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1901963

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档