2009-12-14 11 views
5

मुझे वर्तमान में एक संदेश खोने का मुद्दा है। यह त्रुटि शायद ही कभी होती है, लेकिन अक्सर परेशान होने के लिए पर्याप्त होती है। यहां समस्या का संदर्भ दिया गया है:क्या MSMQ MessageQueue.Peek का उपयोग कर संदेशों को खोना संभव है?

  • मैंने Windows 2003 सर्वर पर एक MSMQ, goldmine_service_queue पर संदेश पत्रिका चालू कर दी है।
  • मैं साबित कर सकता हूं कि संदेश संदेश पत्रिका में संदेश प्रकट होने के बाद से goldmine_service_queue में डाला जा रहा है। यह जानकारी संदेश गायब होने के बारे में समय की जानकारी देती है।
  • लॉगिंग फ़ंक्शन http://logging.apache.org/log4net/index.html
  • लॉग्स त्रुटियों को नहीं दिखाते हैं।
  • कार्यकर्ता फ़ंक्शन (नीचे दिखाया गया) विंडोज सेवा के थ्रेड के भीतर निष्पादित करता है। कतार से संदेशों (कार्य वस्तुओं) पर ध्यान देने और उन्हें संसाधित करने के लिए यह ज़िम्मेदार है।
  • लॉग से, मुझे दृढ़ता से संदेह है कि मेरा मुद्दा MessageQueue.Peek और टाइम आउट व्यवहार से संबंधित हो सकता है।

क्या टाइमआउट और संदेश एक ही समय में होने के लिए संभव है? क्या इस त्रुटि से बचने में मदद के लिए सर्विस स्टॉप जांच को संभालने का मेरे लिए एक बेहतर तरीका है?

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

    } 

उत्तर

5

मुझे नहीं लगता कि कोई संदेश एक त्वरित समीक्षा के आधार पर याद किया जाना चाहिए, लेकिन आप दौड़ की स्थिति के लिए गुंजाइश की बहुत सारी के साथ एक बहुत अजीब तरह से काम कर रहे हैं।

क्यों न केवल संदेश प्राप्त करें और इसे ProcessMessage पर पास करें (यदि ProcessMessage विफल रहता है, तो आप वैसे भी पढ़ रहे हैं)। यदि आपको एकाधिक रिसीवरों को संभालने की आवश्यकता है, तो एमएसएमक्यू लेनदेन में प्राप्त करें ताकि संदेश अन्य रिसीवर के लिए अनुपलब्ध हो लेकिन लेनदेन पूरा होने तक कतार से हटाया न जाए।

इसके अलावा, कतार को मतदान करने के बजाय, एसिंक्रोनस प्राप्त क्यों न करें और धागा पूल पूरा होने को संभालने दें (जहां आपको EndReceive पर कॉल करना होगा)। यह एक धागा बांधने से बचाता है, और आपको विशेष केस सेवा बंद करने की आवश्यकता नहीं है (संदेश कतार बंद करें और फिर MessageQueue.ClearConnectionCache(); पर कॉल करें)।

इसके अलावा, धागे को छोड़ना बाहर निकलने का एक बहुत ही बुरा तरीका है, बस थ्रेड के प्रारंभ समारोह से वापस लौटें।

+0

प्रतिक्रिया के लिए धन्यवाद: - दौड़ की स्थितियों के बारे में: मुझे यकीन नहीं है कि मैं उन रेस स्थितियों को देखता हूं जिन्हें आप उल्लेख कर रहे हैं। Http://msdn.microsoft.com/en-us/library/t5te2tk0.aspx के अनुसार, MessageQueue.Peek (टाइमआउट) एक अवरुद्ध कॉल है। - मैं एसिंक पैटर्न का उपयोग करने के बारे में चिंतित हूं क्योंकि ProcessMessage कुछ COM ऑपरेशंस करता है। मुझे नहीं पता कि ये ऑपरेशन थ्रेड सुरक्षित हैं या नहीं। मैं चोटी के बजाय रिसीव() का उपयोग करने की कोशिश करने के ठीक हूं, सिवाय इसके कि मुझे नहीं पता कि सर्विस स्टॉप के कारण लूप को रोकने का अवसर कैसे बनाया जाए। –

+0

पुन: 'ProcessMessage' में COM: कोई समस्या नहीं होनी चाहिए यदि केवल एक थ्रेड 'ProcessMessage' चल रहा है (जिसे' प्रक्रिया मैसेज 'पूरा होने के बाद ही एक नया एसिंक प्राप्त करके एसिंक केस में हासिल किया जा सकता है। async में यदि आप कतार को बंद करते हैं (और कैश फ्लश करें --- कुछ खोजों के आधार पर यह वास्तव में कनेक्शन को बंद करने के लिए आवश्यक प्रतीत होता है) और कोई लंबित प्राप्तकर्ता रद्द कर दिया जाएगा। रद्द करने के लिए कोई लूप नहीं है। – Richard

1

मैं यह बदलना चाहता हूं कि currentMessage = q.Peek(new TimeSpan(0,0,30)); से currentMessage = q.Receive(); आपकी समस्या को ठीक करेगा। मैं सटीक संदर्भ में गुजरने वाले संदेश के लिए एमएसएमक्यू का उपयोग कर रहा हूं लेकिन यह निर्धारित करने के लिए कि क्या वे कतार खाली है या नहीं, केवल peek (और टाइमआउट अपवाद की अपेक्षा करें) का उपयोग करें। Receive पर कॉल अवरुद्ध है हालांकि तदनुसार योजना बनाएं।

संपादित करें: आपके अपवाद को पकड़ने के लिए भी - आप यह जांच सकते हैं कि त्रुटि अपवाद की तुलना करके आपका अपवाद टाइमआउट अपवाद है या नहीं।

mqe.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout 

जहां आपका संदेश कतार अपवाद है। आप स्ट्रिंग तुलना से बेहतर पसंद कर सकते हैं।

+0

मैं 'संदेश आरएसपी = colaStatus.ReceiveByCorrelationId (सहसंबंध आईडी, नया टाइमस्पैन (0, टाइमऑट, 0)); 'मैं उलझन में हूं अगर टाइमआउट के लिए 5 मिनट बहुत उच्च स्तर है। आईएमएचओ, मुझे लगता है कि बेहतर 1 मिनट से भी कम है। – Kiquenet

3

बस कुछ टिप्पणियां स्पष्ट करने के लिए कि एमएसएमक्यू कैसे काम करता है।

"मैं साबित कर सकता हूं कि संदेश संदेश पत्रिका में संदेश प्रकट होने के बाद से सोनामाइन_सर्व_क्यू में संदेश डाला जा रहा है।

संदेश जर्नल कतार में जाता है जब मूल संदेश goldmine_service_queue से हटा दिया जाता है। तो आप कह सकते हैं कि संदेश सफलतापूर्वक कतार में वितरित किया गया था और सफलतापूर्वक कतार से हटा दिया गया था।

"मुझे दृढ़ता से संदेह है कि मेरा मुद्दा MessageQueue.Peek और समय व्यवहार से संबंधित हो सकता है।"

एक Peek कतार से संदेश को हटाने के लिए कुछ भी नहीं करता है। केवल "q.Receive();" क्या वो। आपके कोड में, संदेश को देखा जा रहा है और प्राप्त होने के बीच कोई स्पष्ट संबंध नहीं है। "Q.Receive();" बस कतार के शीर्ष से संदेश प्राप्त करें "। एक बहु थ्रेडेड वातावरण में, आप संदेशों को असंगत रूप से पढ़ने की उम्मीद कर सकते हैं - कुछ को कई बार देखा जा सकता है और संसाधित किया जा सकता है। आपको Peeked संदेश की आईडी प्राप्त करना चाहिए और ReceiveByID का उपयोग करना चाहिए ताकि आप केवल देखे गए संदेश प्राप्त कर सकें।