Исключение прерывания потока ASP.NET C #?

Я пытаюсь создать небольшого почтового работника, который будет отправлять мои электронные письма. Почтовый работник работает в своем собственном потоке. Global.asax запускает поток, а затем он выполняется в течение одного раунда, прежде чем выбросить это исключение. Пытался узнать, куда он его кидает, но каждый раз вроде по разному. Записи печатаются в текстовый файл, чтобы он работал, может быть, функции удаления?

Это выброшенное исключение:

Запуск нового раунда в цикле for-loop обработчика электронной почты
Переход в режим сна в for-loop обработчика электронной почты
Первое случайное исключение типа 'System.Threading.ThreadAbortException' произошло в mscorlib.dll
Исключение типа 'System.Threading.ThreadAbortException' произошло в mscorlib.dll, но не было обработано в пользовательском коде

Это код для EmailWorker

public static class EmailWorker
{
    public static void Work()
    {
        TimeSpan sleepTime = new TimeSpan(0, 1, 0);

        for (; ; )
        {
            Debug.WriteLine("Starting a new round in the email worker for-loop");
            try
            {
                // Get the records
                CS_Code.UtopiaDataContext db = new CS_Code.UtopiaDataContext(); 
                List<CS_Code.Global_Email> emailsToSend = (from xx in db.Global_Emails select xx).ToList();


                // Write the records to a file (for now)
                TextWriter writer = new StreamWriter(@"test.txt", true); // For debugging
                foreach (var email in emailsToSend)
                    writer.WriteLine("To: " + email.Email_Address + ", Subject: " + email.Subject + ", uid:" + email.UserName.ToString());
                writer.Close();
                writer.Dispose();

                // Delete the used records from the database
                foreach (var email in emailsToSend)
                    db.Global_Emails.DeleteOnSubmit(email);
                db.SubmitChanges();
                db.Dispose();


                Debug.WriteLine("Going to sleep in the email worker for-loop");
                Thread.Sleep(sleepTime); // Sleep for 1 minute.
                Debug.WriteLine("Just woke up in the email worker for-loop");
            }
            catch (Exception e)
            {               
                Debug.WriteLine(e.Message);
                break;
            }
        }
    }
}

Это файл global.asax, который запускает все:

private static Thread EmailWorkerThread { get; set; }

void Application_Start(object sender, EventArgs e)
{
    // Email worker thread
    if ((EmailWorkerThread == null) || (!EmailWorkerThread.IsAlive))
    {
        ThreadStart ts = new ThreadStart(EmailWorker.Work);
        EmailWorkerThread = new Thread(ts);
        EmailWorkerThread.Start();
    }
}

void Application_End(object sender, EventArgs e)
{
    // Email worker thread
    if ((EmailWorkerThread != null) || (EmailWorkerThread.IsAlive))
        EmailWorkerThread.Abort();
    EmailWorkerThread = null;
}

person Patrick    schedule 17.12.2010    source источник


Ответы (5)


Создаваемый вами поток прерывается asp.net. Создание длительных потоков - главный запрет asp.net.

У нас есть рабочий обходной путь, которым мы не гордимся ... Создайте таймер для обработки ожидающих писем.

static Timer processTimer; // declare static at service level

// At the static constructor:
processTimer = new Timer(new TimerCallback(TimerTick), 60000, 10000, defaultInterval); //wait a minute before begin (dueTime = 60000)

Чтобы быть особенно осторожным, в событии Timer_Tick обработайте не более N писем, поэтому тик таймера закончится, и появится новый ...

Это работает в нашей производственной среде ...

person Gerardo Grignoli    schedule 17.12.2010
comment
Вот почему вы перемещаете то, что необходимо для круглосуточной работы, из проекта ASP.NET в службу Windows. - person Roman Royter; 16.03.2011

Вам нужно переместить EmailWorker из ASP.NET в службу Windows. Вы можете общаться между своей веб-страницей и службой через WCF. ASP.NET не предназначен для длительных задач.

person Roman Royter    schedule 15.03.2011

ThreadAbortException возникает, когда ваше приложение завершает работу и вы вызываете EmailWorkerThread.Abort(). Это ожидаемое поведение, и оно происходит в случайных местах, потому что код может быть в разных «местах», когда Application_End вызывает Abort() в потоке.

Согласно MSDN ThreadAbortException является особым исключением, которое всегда запускается повторно даже после обработки вашим кодом. Он предназначен для того, чтобы сообщить вам, что поток закрывается, чтобы дать вам возможность очистить его.

Ваше приложение, скорее всего, завершает работу, потому что IIS завершает работу рабочего процесса после определенного времени простоя или какого-либо другого наложенного ограничения. Опять же, этого следовало ожидать, приложения ASP.NET, как правило, имеют «ограниченное время жизни», поэтому такие длительные потоки, как этот, на самом деле не очень хорошая идея.

Я не уверен, в чем был ваш точный вопрос, но, надеюсь, я ответил на него.

person CodingGorilla    schedule 17.12.2010

Дочерний поток может существовать только до тех пор, пока жив родительский поток. Несмотря на то, что у вас есть поток, определенный на уровне приложения, я не могу себе представить, что этот поток действительно выживет за пределами потока HttpRequest. Для меня это означает, что в момент завершения вашего потока запросов ваш дочерний EmailWorkerThread завершается. Поскольку поток спит, следующая строка пытается выполнить, но не может, потому что поток HttpRequest уже выполнил свой курс.

person Joel Etherton    schedule 17.12.2010
comment
Это неправда, вы можете запускать потоки в приложении, как он, и они не привязаны к какому-либо конкретному потоку запроса. Его исключение возникает из-за того, что его код сообщает потоку Abort(). - person CodingGorilla; 17.12.2010
comment
@Coding Gorilla - Где? Единственное прерывание, которое я вижу, - это конец приложения. Если он не привязан к потоку запроса, то почему бы не сработать окончательная запись отладки перед прерыванием? У меня такое случалось раньше с другим использованием потоков в Asp.Net, но, надо признать, я никогда не пытался помещать объявление потока в код уровня приложения. - person Joel Etherton; 17.12.2010
comment
Я считаю, что последний Debug.Write(e.Message) действительно стреляет. Если вы посмотрите на его исключение: An exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll but was not handled in user code. Это будет последнее сообщение: если вы прочтете документацию MSDN на ThreadAbortException, вы никогда не сможете полностью поймать его, он всегда выкидывается заново. - person CodingGorilla; 17.12.2010

ThreadAbortException, как следует из названия, выдается, когда поток работает и прерывается. Это происходит в этом месте:

 EmailWorkerThread.Abort();

Его невозможно поймать, и это происходит, когда ваше приложение заканчивается.

Лучшей реализацией было бы заменить бесконечный цикл на с возможностью отмены петля.

person Aliostad    schedule 17.12.2010