/// <summary>
        /// Asynchronous callback method. Not in use.
        /// </summary>
        /// <param name="result"></param>
        internal static void MessageSent(IAsyncResult result)
        {
            MailTransmissionDelegate asyncTransmitter = (MailTransmitter.MailTransmissionDelegate)result.AsyncState;

            try
            {
                asyncTransmitter.EndInvoke(result);
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.ToString());
                ExceptionMail.Send(e);
            }

            lock (lockObject)
            {
                outstandingTransmissions--;
            }
        }
Exemple #2
0
        internal static void MailSent(IAsyncResult result)
        {
            lock (lockObject)
            {
                MailTransmissionAsyncState asyncState       = (MailTransmissionAsyncState)result.AsyncState;
                MailTransmissionDelegate   asyncTransmitter = asyncState.dlgt;
                OutboundMailRecipient      recipient        = asyncState.recipient;
                try
                {
                    asyncTransmitter.EndInvoke(result);

                    try
                    {
                        recipient.Delete();
                        recipient.OutboundMail.IncrementSuccesses();
                    }
                    catch (Exception ex)
                    {
                        // whatever.. The mail is sent, but we couldn't mark it as such, probably a database failure.
                        asyncState.exception = new RemoveRecipientException("Couldn't remove mail recipient.", ex);
                        ExceptionMail.Send(asyncState.exception, true);
                    }
                }
                catch (ReportAndRetryRecipientException e)
                {
                    asyncState.exception = e;
                    Debug.WriteLine(e.ToString());
                    ExceptionMail.Send(e, true);
                }
                catch (RetryRecipientException e)
                {
                    // No action - handled in async delegate - retry this mail
                    asyncState.exception = e;
                }
                catch (Exception e)
                {
                    asyncState.exception = e;

                    try
                    {
                        recipient.Delete();
                        recipient.OutboundMail.IncrementFailures();

                        if (e is InvalidRecipientException)
                        {
                            if (recipient.Person != null && recipient.Person.EMailIsInvalid == false)
                            {
                                //Mark address as invalid.
                                recipient.Person.EMailIsInvalid = true;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        // Return this exception in asyncState since it is important to stop flooding.
                        asyncState.exception =
                            new RemoveRecipientException("Couldn't remove mail recipient after exception.", ex);
                        ExceptionMail.Send(asyncState.exception, true);  //Report the secondary exception
                    }


                    Debug.WriteLine(e.ToString());
                    ExceptionMail.Send(e, true);
                }

                asyncState.callbackCompleted = true;
            }
        }
Exemple #3
0
        public static void Run()
        {
            // If there is mail in the outbound mail queue, do not add more. (This is a primitive
            // protection against dupes. Better will come that doesn't force idle time like this.)

            lock (lockObject)
            {
                if (mailQueueSize > 0)
                {
                    // return;
                }
            }

            // Look for a mail to process, or keep processing.
            OutboundMails mails = OutboundMails.GetTopUnprocessed(100);

            mailQueueSize = 0;

            if (mails.Count == 0)
            {
                // no unprocessed mail, everybody's happy
                return;
            }

            int maxBatchSize = 20; // Total number of recipients to process across all mails

            foreach (OutboundMail mail in mails)
            {
                // If we have already processed past our limit, return for now.
                if (maxBatchSize < 1)
                {
                    return;
                }

                // We are continuing to process, and starting with a fresh outbound mail.

                // Is this the first time we touch this mail?
                if (mail.StartProcessDateTime.Year < 2000)
                {
                    // Yes! Mark it as started and mail our author.
                    mail.StartProcessDateTime = DateTime.Now;

                    if (mail.MailType == (int)TypedMailTemplate.TemplateType.MemberMail ||
                        mail.MailType == (int)TypedMailTemplate.TemplateType.OfficerMail)     // TODO: Set special flag
                    {
                        string mailBody = string.Empty;

                        new MailTransmitter(
                            Strings.MailSenderName, Strings.MailSenderAddress, "Mail transmission begins: " + mail.Title,
                            mailBody, Person.FromIdentity(mail.AuthorPersonId), true).Send();
                    }
                }

                int batchSize = maxBatchSize;

                // If we are debugging, and stepping through this program, avoid the misery of many simultaneous threads.

                if (Debugger.IsAttached)
                {
                    batchSize = 1; // Do NOT multithread while debugging
                }

                while (true)
                {
                    if (!Debugger.IsAttached)
                    {
                        // HeartBeater.Instance.Beat();
                        //Tick the heartbeat to stop exernal restart if this takes a lot of time, but only if not debugging.
                    }

                    OutboundMailRecipients recipients = mail.GetNextRecipientBatch(batchSize);

                    maxBatchSize -= recipients.Count; // Decrement number of recipients to process on next mail, if any

                    if (recipients.Count == 0)
                    {
                        // This mail is complete!

                        mail.SetProcessed();

                        if (mail.MailType == (int)TypedMailTemplate.TemplateType.MemberMail ||
                            mail.MailType == (int)TypedMailTemplate.TemplateType.OfficerMail)
                        // TODO: Set special flag
                        {
                            string body = "Your mail has completed transmitting to " +
                                          mail.RecipientCount.ToString("#,##0") +
                                          " intended recipients. Out of these, " +
                                          mail.RecipientsFail.ToString("#,##0") +
                                          " failed because of invalid, empty, or otherwise bad e-mail addresses. These people have not received your message.\r\n";

                            new MailTransmitter(
                                Strings.MailSenderName, Strings.MailSenderAddress,
                                "Mail transmission completed: " + mail.Title, body,
                                Person.FromIdentity(mail.AuthorPersonId),
                                true).Send();
                        }

                        if (maxBatchSize < 1)
                        {
                            return;
                        }

                        break; //the while loop
                    }
                    List <IAsyncResult> sendInProgress  = new List <IAsyncResult>();
                    List <WaitHandle>   waitHandlesList = new List <WaitHandle>();
                    foreach (OutboundMailRecipient recipient in recipients)
                    {
                        // Skip known invalid mail addresses
                        if (recipient.Person != null &&
                            (recipient.Person.EMailIsInvalid || recipient.Person.MailUnreachable))
                        {
                            lock (lockObject)
                            {
                                recipient.Delete();
                                recipient.OutboundMail.IncrementFailures();
                            }

                            continue;
                        }

                        // Start the transmission process, asynchronously

                        lock (lockObject)
                        {
                            MailTransmissionDelegate   asyncTransmitter = TransmitOneMail;
                            MailTransmissionAsyncState asyncState       = new MailTransmissionAsyncState();
                            asyncState.dlgt      = asyncTransmitter;
                            asyncState.recipient = recipient;
                            IAsyncResult asyncResult = asyncTransmitter.BeginInvoke(recipient, MailSent, asyncState);
                            sendInProgress.Add(asyncResult);
                            waitHandlesList.Add(asyncResult.AsyncWaitHandle);
                            mailQueueSize++;
                        }

                        Thread.Sleep(25);  // Allow some time
                    }

                    // now wait for them to finish;
                    int      numberStillExecuting = sendInProgress.Count;
                    int      numberExecutingLast  = numberStillExecuting + 1;
                    DateTime lastProgress         = DateTime.Now;


                    while (numberStillExecuting > 0)
                    {
                        WaitHandle.WaitAny(waitHandlesList.ToArray(), 100, true);
                        lock (lockObject)
                        {
                            numberStillExecuting = 0;
                            waitHandlesList      = new List <WaitHandle>();

                            for (int i = 0; i < sendInProgress.Count; ++i)
                            {
                                IAsyncResult iares = sendInProgress[i];
                                MailTransmissionAsyncState asyncState = (MailTransmissionAsyncState)iares.AsyncState;

                                if (asyncState.dlgt != null)
                                {
                                    if (!asyncState.callbackCompleted)
                                    {
                                        waitHandlesList.Add(iares.AsyncWaitHandle);
                                        numberStillExecuting++;
                                    }
                                    else
                                    {
                                        //Just finalised
                                        if (asyncState.exception != null)
                                        {
                                            if (asyncState.exception is RetryRecipientException)
                                            {
                                                //Failed in sending due to some reason that can clear up by itself.
                                                asyncState.dlgt = null;
                                            }
                                            else
                                            {
                                                //Make sure recipient is deleted
                                                try
                                                {
                                                    asyncState.recipient.Delete();

                                                    // if RemoveRecipientException everything went ok except for the removal
                                                    if (asyncState.exception is RemoveRecipientException)
                                                    {
                                                        asyncState.recipient.OutboundMail.IncrementSuccesses();
                                                    }

                                                    asyncState.dlgt = null; // mark as done;
                                                    mailQueueSize--;
                                                }
                                                catch
                                                {
                                                    //Keep looping until recipient removed
                                                    numberStillExecuting++;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        if (numberExecutingLast != numberStillExecuting)
                        {
                            lastProgress = DateTime.Now;
                        }

                        numberExecutingLast = numberStillExecuting;

                        if (lastProgress.AddSeconds(60 * 2) < DateTime.Now)
                        {
                            // since last change, something must have hanged
                            lock (lockObject)
                            {
                                mailQueueSize = -1000;
                            }
                            throw new Exception("Timeout in MailProcessor");
                        }
                    }
                }
            }
        }
Exemple #4
0
        public static void Run ()
        {
            // If there is mail in the outbound mail queue, do not add more. (This is a primitive
            // protection against dupes. Better will come that doesn't force idle time like this.)

            lock (lockObject)
            {
                if (mailQueueSize > 0)
                {
                    // return;
                }
            }

            // Look for a mail to process, or keep processing.
            OutboundMails mails = OutboundMails.GetTopUnprocessed(100);
            mailQueueSize = 0;

            if (mails.Count == 0)
            {
                // no unprocessed mail, everybody's happy
                return;
            }

            int maxBatchSize = 20; // Total number of recipients to process across all mails

            foreach (OutboundMail mail in mails)
            {

                // If we have already processed past our limit, return for now.
                if (maxBatchSize < 1)
                {
                    return;
                }

                // We are continuing to process, and starting with a fresh outbound mail.

                // Is this the first time we touch this mail?
                if (mail.StartProcessDateTime.Year < 2000)
                {
                    // Yes! Mark it as started and mail our author.
                    mail.StartProcessDateTime = DateTime.Now;

                    if (mail.MailType == (int)TypedMailTemplate.TemplateType.MemberMail
                        || mail.MailType == (int)TypedMailTemplate.TemplateType.OfficerMail) // TODO: Set special flag
                    {
                        string mailBody = string.Empty;

                        new MailTransmitter(
                            Strings.MailSenderName, Strings.MailSenderAddress, "Mail transmission begins: " + mail.Title,
                            mailBody, Person.FromIdentity(mail.AuthorPersonId), true).Send();
                    }
                }

                int batchSize = maxBatchSize;

                // If we are debugging, and stepping through this program, avoid the misery of many simultaneous threads.

                if (System.Diagnostics.Debugger.IsAttached)
                {
                    batchSize = 1; // Do NOT multithread while debugging
                }

                while (true)
                {
                    if (!System.Diagnostics.Debugger.IsAttached)
                    {
                        HeartBeater.Instance.Beat();
                            //Tick the heartbeat to stop exernal restart if this takes a lot of time, but only if not debugging.
                    }

                    OutboundMailRecipients recipients = mail.GetNextRecipientBatch(batchSize);

                    maxBatchSize -= recipients.Count; // Decrement number of recipients to process on next mail, if any

                    if (recipients.Count == 0)
                    {
                        // This mail is complete!

                        mail.SetProcessed();

                        if (mail.MailType == (int)TypedMailTemplate.TemplateType.MemberMail
                            || mail.MailType == (int)TypedMailTemplate.TemplateType.OfficerMail) // TODO: Set special flag
                        {
                            string body = "Your mail has completed transmitting to " + mail.RecipientCount.ToString("#,##0") +
                                          " intended recipients. Out of these, " + mail.RecipientsFail.ToString("#,##0") +
                                          " failed because of invalid, empty, or otherwise bad e-mail addresses. These people have not received your message.\r\n";

                            new Mail.MailTransmitter(
                                Strings.MailSenderName, Strings.MailSenderAddress,
                                "Mail transmission completed: " + mail.Title, body, Person.FromIdentity(mail.AuthorPersonId),
                                true).Send();
                        }

                        if (maxBatchSize < 1)
                        {
                            return;
                        }

                        break; //the while loop
                    }
                    else
                    {
                        List<IAsyncResult> sendInProgress = new List<IAsyncResult>();
                        List<WaitHandle> waitHandlesList = new List<WaitHandle>();
                        foreach (OutboundMailRecipient recipient in recipients)
                        {
                            // Skip known invalid mail addresses
                            if (recipient.Person != null
                                && (recipient.Person.EMailIsInvalid || recipient.Person.MailUnreachable))
                            {
                                lock (lockObject)
                                {
                                    recipient.Delete();
                                    recipient.OutboundMail.IncrementFailures();
                                }

                                continue;
                            }

                            // Start the transmission process, asynchronously

                            lock (lockObject)
                            {
                                MailTransmissionDelegate asyncTransmitter = new MailTransmissionDelegate(TransmitOneMail);
                                MailTransmissionAsyncState asyncState = new MailTransmissionAsyncState();
                                asyncState.dlgt = asyncTransmitter;
                                asyncState.recipient = recipient;
                                IAsyncResult asyncResult = asyncTransmitter.BeginInvoke(recipient, new AsyncCallback(MailSent), asyncState);
                                sendInProgress.Add(asyncResult);
                                waitHandlesList.Add(asyncResult.AsyncWaitHandle);
                                mailQueueSize++;
                            }

                            System.Threading.Thread.Sleep(25); // Allow some time
                        }

                        // now wait for them to finish;
                        int numberStillExecuting = sendInProgress.Count;
                        int numberExecutingLast = numberStillExecuting + 1;
                        DateTime lastProgress = DateTime.Now;


                        while (numberStillExecuting > 0)
                        {
                            WaitHandle.WaitAny(waitHandlesList.ToArray(), 100, true);
                            lock (lockObject)
                            {
                                numberStillExecuting = 0;
                                waitHandlesList = new List<WaitHandle>();

                                for (int i = 0; i < sendInProgress.Count; ++i)
                                {
                                    IAsyncResult iares = sendInProgress[i];
                                    MailTransmissionAsyncState asyncState = (MailTransmissionAsyncState)iares.AsyncState;

                                    if (asyncState.dlgt != null)
                                    {
                                        if (!asyncState.callbackCompleted)
                                        {
                                            waitHandlesList.Add(iares.AsyncWaitHandle);
                                            numberStillExecuting++;
                                        }
                                        else
                                        {
                                            //Just finalised
                                            if (asyncState.exception != null)
                                            {
                                                if (asyncState.exception is RetryRecipientException)
                                                {
                                                    //Failed in sending due to some reason that can clear up by itself.
                                                    asyncState.dlgt = null;
                                                }
                                                else
                                                {
                                                    //Make sure recipient is deleted
                                                    try
                                                    {
                                                        asyncState.recipient.Delete();

                                                        // if RemoveRecipientException everything went ok except for the removal
                                                        if (asyncState.exception is RemoveRecipientException)
                                                            asyncState.recipient.OutboundMail.IncrementSuccesses();

                                                        asyncState.dlgt = null; // mark as done;
                                                        mailQueueSize--;

                                                    }
                                                    catch
                                                    {   //Keep looping until recipient removed
                                                        numberStillExecuting++;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }

                            if (numberExecutingLast != numberStillExecuting)
                                lastProgress = DateTime.Now;

                            numberExecutingLast = numberStillExecuting;

                            if (lastProgress.AddSeconds(60 * 2) < DateTime.Now)
                            {
                                // since last change, something must have hanged
                                lock (lockObject)
                                {
                                    mailQueueSize = -1000;
                                }
                                throw new Exception("Timeout in MailProcessor");
                            }
                        }
                    }
                }
            }
        }