Pregunta

Estoy tratando de construir un pequeño trabajador de correo electrónico que envíe mis correos electrónicos. El trabajador de correo electrónico opera en su propio hilo. El Global.asax inicia el hilo y luego se ejecuta para una ronda antes de lanzar esta excepción. He estado tratando de averiguar dónde lo arroja, pero parece ser diferente cada vez. Los registros se imprimen en el archivo de texto para que funcione, ¿tal vez las funciones de eliminación?

Esta es la excepción lanzada:

Comenzar una nueva ronda en el trabajador de correo electrónico For-Loop
Ir a dormir en el trabajador de correo electrónico para el circuito
Una excepción de primera oportunidad del tipo 'System.threading.threadabortException' ocurrió en mscorlib.dll
Una excepción del tipo 'system.threading.threadabortexception' ocurrió en mscorlib.dll pero no se manejó en el código de usuario

Este es el código para el trabajo de correo electrónico

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;
            }
        }
    }
}

Este es el archivo global.asax que inicia todo:

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;
}
¿Fue útil?

Solución

El hilo que está creando está siendo abortado por ASP.NET. La creación de hilos de larga duración es un gran no-no en ASP.NET.

A Tenemos una solución para que funcione, del que no estamos orgullosos ... cree un temporizador que procese los correos electrónicos pendientes.

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)

Para tener más cuidado, en el evento Timer_Tick, manejar en la mayoría de los correos electrónicos de N, por lo que termina el tick timer, y una nueva se eleva ...

Esto está trabajando en nuestro entorno de producción ...

Otros consejos

Debe mover el trabajo de correo electrónico de ASP.NET y al servicio de Windows. Puede comunicarse entre su página web y el servicio a través de WCF. ASP.NET no está destinado a tareas de larga duración.

los ThreadAbortException ocurre cuando su aplicación se apaga y llame EmailWorkerThread.Abort(). Este es el comportamiento esperado y ocurre en lugares aleatorios porque el código puede estar en diferentes "puntos" cuando el Application_End llamadas Abort() en el hilo.

Según MSDN, la ThreadAbortException es una excepción especial que siempre se vuelve a llenar incluso después de ser manejada por su código. Está destinado a hacerle saber que el hilo se está cerrando para darle la oportunidad de limpiar.

Es probable que su aplicación esté apagando porque IIS está cerrando el proceso del trabajador después de una cantidad establecida de tiempo de inactividad, o alguna otra limitación impuesta. Una vez más, esto es de esperar, las aplicaciones ASP.NET tienden a tener "vidas limitadas", por lo que ejecutar hilos como este no es realmente una buena idea.

No estoy seguro de cuál fue su pregunta exacta, pero espero que la respondiera.

El hilo infantil solo puede vivir mientras el hilo principal esté vivo. Aunque tiene un hilo definido en lo que parece ser el nivel de aplicación, no puedo imaginar que este hilo sobrevive fuera del hilo HTTPRequest. Para mí, esto significa que en el momento en que su hilo de solicitud termina, su hijo, su hijo, TworkerThread termina. Dado que el hilo está durmiendo, la siguiente línea intenta ejecutar, pero no puede porque el hilo HTTPRequest ya ha ejecutado su curso.

ThreadAbortException Como su nombre lo indica, se arroja cuando un hilo funciona y se aborta. Esto sucede en este lugar:

 EmailWorkerThread.Abort();

No se puede atrapar y sucede cuando termina la aplicación.

Una mejor implementación sería reemplazar el bucle infinito con cancelable círculo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top