2012-03-08 16 views
9

मैं एक समाचार पत्र प्रणाली है कि मुझे निर्दिष्ट करने के लिए जो सदस्य समाचार पत्र प्राप्त करना चाहिए की अनुमति देता है बनाया है। मैं फिर उन सदस्यों की सूची के माध्यम से लूप करता हूं जो मानदंडों को पूरा करते हैं और प्रत्येक सदस्य के लिए, मैं एक व्यक्तिगत संदेश उत्पन्न करता हूं और उन्हें ईमेल को असंकालिक रूप से भेजता हूं।आंशिक काम किया जा रहा है दो बार (ThreadPool.QueueUserWorkItem)

जब मैं ईमेल भेजने, मैं ThreadPool.QueueUserWorkItem उपयोग कर रहा हूँ।

किसी कारण के लिए, सदस्यों के एक सबसेट दो बार ईमेल हो रही है। मेरे आखिरी बैच में, मैं केवल 712 सदस्यों को भेज रहा था, फिर भी कुल 7 9 8 संदेश भेजे जा रहे थे।

मैं उन संदेशों को बाहर भेजा प्रवेश करने रहा हूँ और मैं यह बताने के लिए है कि पहले 86 सदस्यों संदेश दो बार प्राप्त कर रहा था। यहाँ लॉग (क्रम में संदेश भेजा गया)

No. Member Date 
1. 163992 3/8/2012 12:28:13 PM 
2. 163993 3/8/2012 12:28:13 PM 
... 
85. 164469 3/8/2012 12:28:37 PM 
86. 163992 3/8/2012 12:28:44 PM 
87. 163993 3/8/2012 12:28:44 PM 
... 
798. 167691 3/8/2012 12:32:36 PM 

प्रत्येक सदस्य एक बार समाचार पत्र प्राप्त करना चाहिए, फिर भी, जैसा कि आप देख सकते हैं सदस्य 163,992 प्राप्त करता है संदेश # 1 और # 86 है, सदस्य 1639 9 3 संदेश मिला # 2 और # 87; और इसी तरह।

नोट करने के लिए दूसरी बात यह संदेश # 85 और # 86 भेजने के बीच एक 7 सेकंड की देरी थी है।

मैंने कई बार कोड की समीक्षा की है और संभवतः ThreadPool.QueueUserWorkItem को छोड़कर, इसके सभी कारणों के कारण कोड को बहुत अधिक अस्वीकार कर दिया है।

यह पहली बार मैं ThreadPool के साथ काम है, इसलिए मुझे लगता है कि यह से परिचित नहीं हूँ। क्या इस तरह के व्यवहार के कारण कुछ प्रकार की दौड़-स्थिति हो सकती है?

=== --- कोड नमूना --- ===

foreach (var recipient in recipientsToEmail) 
    { 
     _emailSender.SendMemberRegistrationActivationReminder(eventArgs.Newsletter, eventArgs.RecipientNotificationInfo, previewEmail: string.Empty); 
    } 


    public void SendMemberRegistrationActivationReminder(DomainObjects.Newsletters.Newsletter newsletter, DomainObjects.Members.MemberEmailNotificationInfo recipient, string previewEmail) 
    { 
//Build message here ..... 

//Send the message 
      this.SendEmailAsync(fromAddress: _settings.WebmasterEmail, 
           toAddress: previewEmail.IsEmailFormat() 
              ? previewEmail 
              : recipientNotificationInfo.Email, 
           subject: emailSubject, 
           body: completeMessageBody, 
           memberId: previewEmail.IsEmailFormat() 
              ? null //if this is a preview message, do not mark it as being sent to this member 
              : (int?)recipientNotificationInfo.RecipientMemberPhotoInfo.Id, 
           newsletterId: newsletter.Id, 
           newsletterTypeId: newsletter.NewsletterTypeId, 
           utmCampaign: utmCampaign, 
           languageCode: recipientNotificationInfo.LanguageCode); 
     } 

    private void SendEmailAsync(string fromAddress, string toAddress, string subject, MultiPartMessageBody body, int? memberId, string utmCampaign, string languageCode, int? newsletterId = null, DomainObjects.Newsletters.NewsletterTypeEnum? newsletterTypeId = null) 
    { 
     var urlHelper = UrlHelper(); 
     var viewOnlineUrlFormat = urlHelper.RouteUrl("UtilityEmailRead", new { msgid = "msgid", hash = "hash" }); 
     ThreadPool.QueueUserWorkItem(state => SendEmail(fromAddress, toAddress, subject, body, memberId, newsletterId, newsletterTypeId, utmCampaign, viewOnlineUrlFormat, languageCode)); 
    } 
+1

मुझे दौड़ की स्थिति की तरह लग रहा है - यदि आप कतार का उपयोग करते हैं तो क्या आप ThreadPool.QueueUserWorkItem() को कॉल करने से पहले कतार से आइटम हटाते हैं? क्या हम आपका कोड देख सकते हैं? – alexm

+0

मैं किसी अन्य प्रकार की कतार का उपयोग नहीं कर रहा हूं। असल में: सदस्यों को पूरा करने वाले सदस्यों की सूची के माध्यम से लूप, सदस्य के लिए ईमेल जेनरेट करें, विधि में कॉल जोड़ें जो वास्तव में थ्रेडपूल को ईमेल भेजता है। –

+0

डुप्लिकेट से बचने के लिए उन उपयोगकर्ताओं की सूची बनाए रखें जिनके पास – alexm

उत्तर

2

सर्वर पर चल रहे 800+ थ्रेड होने का अच्छा अभ्यास नहीं है! यद्यपि आप थ्रेडपूल का उपयोग कर रहे हैं, थ्रेड को सर्वर पर कतारबद्ध किया जा रहा है और जब भी पुराने थ्रेड पूल पर वापस आते हैं और संसाधन को छोड़ देते हैं। इसमें सर्वर पर कई मिनट लग सकते हैं और उस समय के दौरान रेस कंडीशन या कंसुरेंसी जैसी कई स्थितियां हो सकती हैं। आप के बजाय एक संरक्षित सूची के ऊपर एक काम आइटम, कतार सकता है:

lock (recipientsToEmail) 
{ 
    ThreadPool.QueueUserWorkItem(t => 
     { 
      // enumerate recipientsToEmail and send email 
     }); 
} 
+0

जब मैंने न्यूजलेटर भेजा तो मैं एक समय में एक संदेश भेजते समय पहले से ही ईमेलिंग सिस्टम का लाभ उठा रहा था। वास्तव में इसके बारे में नहीं सोचा था, लेकिन हाँ, 800+ धागे होने से गलत दृष्टिकोण की तरह लग रहा है। मैंने अपना कोड फिर से बनाया ताकि मैं एक नया धागा स्पिन कर सकूं और इसे न्यूज़लेटर संदेशों को संसाधित कर सकूं। –

1

हालात की जाँच करने के (मैं आप ईमेल भेजने नकली के लिए एक रास्ता है यह सोचते हैं रहा हूँ):

  • डुप्लिकेट ईमेल की संख्या हमेशा वही है? क्या होगा यदि आप इनपुट मानों की संख्या में वृद्धि/कमी करते हैं? क्या यह हमेशा वही उपयोगकर्ता आईडी है जो डुप्लीकेट हैं?
  • SendEmail() महत्व के कुछ भी कर रहा है? (मुझे इसके लिए आपका कोड नहीं दिख रहा है)
  • क्या कोई कारण है कि आप framework's SendAsync() method का उपयोग नहीं कर रहे हैं?
  • क्या आपको मल्टीथ्रेडिंग के बिना वही व्यवहार मिलता है?

यह क्या है इसके लिए, अपनी साइट से थोक ईमेल भेजना - यहां तक ​​कि जब यह पूरी तरह वैध है - हमेशा परेशानी के लायक नहीं है। स्पैम अवरुद्ध सेवाएं बहुत आक्रामक हैं और आप नहीं चाहते हैं कि आपका डोमेन ब्लैकलिस्टेड समाप्त हो। तृतीय पक्ष सेवाएं उस जोखिम को हटाती हैं, कई टूल प्रदान करती हैं, और आपके लिए प्रक्रिया के इस हिस्से को भी प्रबंधित करती हैं।

+0

टिम, वास्तव में SendEmail संदेश की सामग्री लॉग करता है ताकि वे "ऑनलाइन देखें" कर सकें। मुझे नहीं पता था कि SmtpClient को SendAsync विधि थी, मैं उस पर स्विच करूंगा। साथ ही, मैं वास्तव में ईमेल की डिलीवरी को संभालने के लिए SendGrid का उपयोग कर रहा हूं। मैं केवल अपनी साइट पर संदेश उत्पन्न कर रहा हूं और अपने एसएमटीपी सर्वर का उपयोग कर रहा हूं। –

+0

"क्या आपको मल्टीथ्रेडिंग के बिना वही व्यवहार मिलता है?" मेरे लिए पहला बिंदु होगा, साथ ही सूची में डुप्लिकेट किए गए आइटमों की जांच भी करेगा। – remio

3

क्या आप सुनिश्चित हैं कि आप जिस ईमेल को ईमेल भेजने के लिए सदस्यों की सूची प्राप्त करने के लिए चल रहे हैं, उसमें डुप्लिकेट नहीं है? क्या आप दूसरी टेबल में शामिल हो रहे हैं? तुम क्या कर सकता है:

List<DomainObjects.Members.MemberEmailNotificationInfo> list = GetListFromDatabase(); 
list = list.Distinct().ToList(); 
1

यदि यह कोड:

foreach (var recipient in recipientsToEmail) 
{ 
    _emailSender.SendMemberRegistrationActivationReminder(eventArgs.Newsletter 
    ,eventArgs.RecipientNotificationInfo, previewEmail: string.Empty); 
} 

मैचों आप वास्तव में क्या कर रहे हैं क्या ... आप एक स्पष्ट बग है।अर्थात् आप एक foreach कर रहे हैं लेकिन लौटा मूल्य का उपयोग नहीं कर रहे हैं, तो आप recipientsToEmail में प्रत्येक प्रविष्टि के लिए eventArgs.RecipientNotificationInfo पर एक ही ईमेल भेज देंगे।

1

कोड में दो बार प्रदर्शन करने का एक आम कारण जहां आप पृष्ठभूमि थ्रेड पर कार्य कतार करते हैं, दोषपूर्ण त्रुटि हैंडलिंग है। यह सुनिश्चित करने के लिए आप अपने कोड को दोबारा जांच सकते हैं कि अगर कोई त्रुटि है कि हमेशा पुन: प्रयास करें, त्रुटि के प्रकार के बावजूद (कुछ त्रुटियां एक पुन: प्रयास करें; अन्य नहीं)।

यह कहकर कि, आपके द्वारा पोस्ट किया गया कोड में आपके प्रश्न का निश्चित उत्तर देने के लिए पर्याप्त जानकारी शामिल नहीं है; कई संभावनाएं हैं।

FWIW, क्या आप जानते हैं कि SmtpClient कक्षा में SendAsync() विधि है, जिसके लिए एक अलग कार्यकर्ता धागे के उपयोग की आवश्यकता नहीं है?

1

अपने कोड नमूने में, हम नहीं देख सकते हैं, जहां आपके प्रवेश होता है।

शायद ईमेल भेजता है जो ईमेल भेजता है गलती से सोचा कि कुछ गलत हुआ, सिस्टम फिर से प्रयास किया, जिसके परिणामस्वरूप एक ईमेल दो बार भेजा गया।

साथ ही, जैसा कि अन्य उत्तरों और टिप्पणी में लिखा गया है, मैं फिर से जांच करूंगा कि मुझे प्राप्तकर्ताओं की सूची में डुप्लिकेट प्रविष्टियां नहीं मिलती हैं, और गैर-समांतर संदर्भ में इसका परीक्षण करती है।

संबंधित मुद्दे