La mejor manera de ejecutar tareas programadas [cerrado]

229

Hoy hemos creado una aplicación de consola para ejecutar las tareas programadas para nuestro sitio web ASP.NET. Pero creo que este enfoque es un poco propenso a errores y difícil de mantener. ¿Cómo ejecuta su tarea programada (en un entorno Windows / IIS / ASP.NET)

Actualizar:

Ejemplos de tareas:

  • Enviar correo electrónico desde una cola de correo electrónico en la base de datos
  • Eliminar objetos obsoletos de la base de datos
  • Recuperar estadísticas de Google AdWords y llenar una tabla en la base de datos.
Niels Bosma
fuente
¿Cuál es un ejemplo de las tareas que está ejecutando?
JeffO
44
Necesitas revisar atrigger.com
Kousha
Si tiene Plesk, puede escribir un vbs y agregarlo
HasanG

Respuestas:

74

Todas mis tareas (que deben programarse) para un sitio web se mantienen dentro del sitio web y se llaman desde una página especial. Luego escribí un servicio simple de Windows que llama a esta página de vez en cuando. Una vez que la página se ejecuta, devuelve un valor. Si sé que hay más trabajo por hacer, vuelvo a ejecutar la página, de lo contrario, la ejecuto en un momento. Esto me ha funcionado muy bien y mantiene toda mi lógica de tareas con el código web. Antes de escribir el sencillo servicio de Windows, utilicé el programador de Windows para llamar a la página cada x minutos.

Otra forma conveniente de ejecutar esto es usar un servicio de monitoreo como Pingdom . Apunte su verificación de http a la página que ejecuta su código de servicio. Haga que la página devuelva resultados que luego se pueden usar para hacer que Pingdom envíe mensajes de alerta cuando algo no está bien.

Brettski
fuente
3
Esta es la solución con la que terminé. En lugar de un servicio web personalizado, uso el planificador de Windows + curl. ¿Cuál es la ventaja de usar un servicio de Windows?
Niels Bosma
16
¿Has mirado la técnica de caducidad del elemento de caché? Creo que encontrará que es una implementación mucho más ideal de un servicio programado: codeproject.com/KB/aspnet/ASPNETService.aspx
Richard Clayton
10
¿Qué impide que un usuario malintencionado (o una araña de motor de búsqueda) llame a esta página y, por lo tanto, provoque la ejecución de sus tareas programadas?
UpTheCreek el
8
Puede detener las llamadas maliciosas almacenando una marca de tiempo estática en la aplicación web y ejecutándose solo si la marca de tiempo no se ha configurado (primera llamada) o si la hora correcta ha expirado desde la última llamada.
Rob Kent
55
Dejo de hacer llamadas maliciosas a mi URL comprobando si la dirección IP es interna o no. No devuelve nada y no hace nada si no es interno a nuestra organización.
user1408767
128

Esta técnica de Jeff Atwood para Stackoverflow es el método más simple que he encontrado. Se basa en el mecanismo de devolución de llamada "elemento de caché eliminado" integrado en el sistema de caché de ASP.NET

Actualización: Stackoverflow ha superado este método. Solo funciona mientras el sitio web se está ejecutando, pero es una técnica muy simple que es útil para muchas personas.

También echa un vistazo a Quartz.NET

ANTES DE CRISTO.
fuente
12
Entonces, ¿qué sucede si la aplicación no se está ejecutando, pero la tarea programada debe suceder?
MichaelGG
2
Esto también podría ralentizar la experiencia del usuario si la tarea tarda un tiempo en ejecutarse esta vez. Prefiero no hacer que el usuario genere mis tareas / mantenimiento por mí.
Brettski
55
¡Esto da miedo como el infierno! Cualquier cosa puede hacer que la aplicación deje de ejecutarse y probablemente solo se reinicie en la próxima solicitud del usuario. Entre esos momentos, tus tareas no se ejecutan!
teedyay
43
Algo que noté hoy en los comentarios a la publicación original del blog: No, we’ve switched to a dedicated task. We definitely outgrew this technique. I do think it’s fine for small sites though!- Jeff Atwood
Joel Coehoorn
3
-1 Hay un gran defecto con este enfoque. Cada vez que se recicla la aplicación, se activa el evento 'CacheItemRemoved' y se ejecutará su tarea programada. En los sitios de producción, esto puede suceder algunas veces al día. No es tan bueno si quieres que la tarea se ejecute semanalmente.
Steven de Salas
30

Crea un servicio personalizado de Windows .

Tenía algunas tareas de misión crítica configuradas como aplicaciones de consola programadas y las encontré difíciles de mantener. Creé un servicio de Windows con un 'latido' que verificaría un horario en mi base de datos cada dos minutos. Funcionó muy bien.

Dicho esto, todavía uso aplicaciones de consola programadas para la mayoría de mis tareas de mantenimiento no críticas. Si no está roto, no lo arregles.

Chris Van Opstal
fuente
77
Para su información, el enlace ahora está muerto.
Charles Burns
1
@CharlesBurns, siempre puede navegar por enlaces muertos con archive.org: web.archive.org/web/20090919131944/http://www.dotheweb.net/…
Nikolay Kostov
17

He encontrado que esto es fácil para todos los involucrados:

  • Cree un método de servicio web como DoSuchAndSuchProcess
  • Cree una aplicación de consola que llame a este método web.
  • Programe la aplicación de consola en el programador de tareas.

Al usar esta metodología, toda la lógica de negocios está contenida en su aplicación web, pero tiene la confiabilidad del administrador de tareas de Windows o de cualquier otro administrador de tareas comerciales para iniciarlo y registrar cualquier información de devolución, como un informe de ejecución. Usar un servicio web en lugar de publicar en una página tiene una pequeña ventaja porque es más fácil obtener datos de retorno de un servicio web.

Daniel Auger
fuente
10

Por qué reinventar la rueda, use la clase Threading y Timer.

    protected void Application_Start()
    {
        Thread thread = new Thread(new ThreadStart(ThreadFunc));
        thread.IsBackground = true;
        thread.Name = "ThreadFunc";
        thread.Start();
    }

    protected void ThreadFunc()
    {
        System.Timers.Timer t = new System.Timers.Timer();
        t.Elapsed += new System.Timers.ElapsedEventHandler(TimerWorker);
        t.Interval = 10000;
        t.Enabled = true;
        t.AutoReset = true;
        t.Start();
    }

    protected void TimerWorker(object sender, System.Timers.ElapsedEventArgs e)
    {
        //work args
    }
Moises Goncalves
fuente
77
No necesita generar un hilo para iniciar un temporizador ...
Zyo
44
Yo tampoco creo que sea una solución ideal.
Idan Shechter
12
@IdanShechter sería bueno decir una razón por la que considera que esta no es una solución ideal
Omu
2
El subproceso podría ser problemático, ya que no es HttpRequest, algunos datos que involucran HttpRequest pueden ser nulos. Por ejemplo HttpRequest .ApplicationPath. Si la tarea está escrita correctamente, funcionará. Otro problema es el reinicio del grupo de aplicaciones. Si el grupo se reinicia con demasiada frecuencia (pérdidas de memoria ...), el trabajador nunca se ejecutará.
Tomas Kubes
2
En caso de que tenga varias instancias ejecutándose (por ejemplo, equilibrio de carga), probablemente no desee esta solución (varias tareas hacen lo mismo)
Illidan
8

Use el Programador de Windows para ejecutar una página web.

Para evitar que el usuario malicous o las arañas de los motores de búsqueda lo ejecuten, cuando configure la tarea programada, simplemente llame a la página web con una cadena de consulta, es decir: mypage.aspx? From = Scheduledtask

Luego, en la carga de la página, simplemente use una condición: if (Request.Querystring ["from"] == "Scheduledtask") {// executetask}

De esta manera, ninguna araña de motor de búsqueda o usuario malintencionado podrá ejecutar su tarea programada.

philberg
fuente
55
Mejor aún, use un algoritmo de hash salado que realmente verifique la cadena de consulta con un poco más de seguridad que una frase mágica. La solicitud sería algo así como mypage.aspx? Salt = foo & hash = 1223523jbhdgu13t1. Solo tiene que tener el mismo algoritmo de hash tanto en el servidor como en el cliente. También agregue un límite estricto en el servidor; guardar cuando se ejecutó y evitar que se ejecute demasiado rápido. Aunque podría ser paranoico.
Nenotlep
14
Aún más seguro, use el Programador de Windows para ejecutar una página web que verifique si la solicitud proviene del propio servidor: Request.IsLocal>> solo el servidor mismo puede ejecutar las tareas programadas, nadie más.
The Conspiracy
¿Tienes más experiencias de tu enfoque? Iba a desarrollar un tipo similar de servicio de nuestra aplicación y ahora no puedo decidir si es mejor llamar a una página con tarea programada o cron, o si usar el sistema de caché.
JayDee
3

Además, si su aplicación usa SQL SERVER, puede usar el Agente SQL para programar sus tareas. Aquí es donde comúnmente ponemos código recurrente basado en datos (recordatorios por correo electrónico, mantenimiento programado, purgas, etc.). Una gran característica integrada con el Agente SQL son las opciones de notificación de fallas, que pueden alertarlo si falla una tarea crítica.

Zachary
fuente
2

No estoy seguro de a qué tipo de tareas programadas te refieres. Si quiere decir cosas como "cada hora, actualice las tareas de tipo foo.xml", utilice el sistema de Tareas Programadas de Windows. (El comando "at" o mediante el controlador). Ejecute una aplicación de consola o solicite una página especial que inicie el proceso.

Editar: debo agregar, esta es una buena manera de hacer que su aplicación IIS también se ejecute en los puntos programados. Supongamos que desea verificar su base de datos cada 30 minutos y enviar recordatorios por correo electrónico a los usuarios sobre algunos datos, puede usar tareas programadas para solicitar esta página y, por lo tanto, obtener el procesamiento de IIS.

Si sus necesidades son más complejas, puede considerar crear un servicio de Windows y hacer que se ejecute un bucle para hacer cualquier procesamiento que necesite. Esto también tiene la ventaja de separar el código para fines de escalado o administración. En el lado negativo, debe lidiar con los servicios de Windows.

MichaelGG
fuente
2

Si posee el servidor, debe usar el programador de tareas de Windows. Utilice AT /? desde la línea de comando para ver las opciones.

De lo contrario, desde un entorno basado en la web, es posible que tenga que hacer algo desagradable como configurar una máquina diferente para realizar solicitudes a una determinada página en un intervalo de tiempo.

t3rse
fuente
2

He usado Abidar con éxito en un proyecto ASP.NET (aquí hay información de fondo ).

El único problema con este método es que las tareas no se ejecutarán si la aplicación web ASP.NET se descarga de la memoria (es decir, debido al bajo uso). Una cosa que intenté es crear una tarea para acceder a la aplicación web cada 5 minutos, mantenerla viva, pero esto no parece funcionar de manera confiable, por lo que ahora estoy usando el programador de Windows y la aplicación de consola básica para hacerlo.

La solución ideal es crear un servicio de Windows, aunque esto podría no ser posible (es decir, si está utilizando un entorno de alojamiento compartido). También facilita un poco las cosas desde una perspectiva de mantenimiento para mantener las cosas dentro de la aplicación web.

Mun
fuente
1

Aquí hay otra forma:

1) Cree una secuencia de comandos web "heartbeat" que se encargue de iniciar las tareas si están DEBIDAS o atrasadas para su lanzamiento.

2) Cree un proceso programado en algún lugar (preferiblemente en el mismo servidor web) que llegue al script web y lo obligue a ejecutarse a intervalos regulares. (p. ej., tarea de programación de Windows que lanza silenciosamente el script de heatbeat usando IE o whathaveyou)

El hecho de que el código de la tarea esté contenido dentro de un script web es simplemente por mantener el código dentro de la base de código de la aplicación web (se supone que ambos dependen el uno del otro), lo que sería más fácil de administrar para los desarrolladores web .

El enfoque alternativo es crear un script / programa ejecutable del servidor que haga que todo el programa funcione por sí mismo y ejecutar el ejecutable como una tarea programada. Esto puede permitir un desacoplamiento fundamental entre la aplicación web y la tarea programada. Por lo tanto, si necesita que sus tareas programadas se ejecuten incluso en el caso de que la aplicación web / base de datos pueda estar inactiva o inaccesible, debe seguir este enfoque.

Matias Nino
fuente
1
@Matias, ¿por qué no simplemente hacer que el proceso programado haga el trabajo real?
LukeH
1

Puede crear fácilmente un servicio de Windows que ejecute código en intervalos utilizando el método 'ThreadPool.RegisterWaitForSingleObject'. Es realmente elegante y bastante fácil de configurar. Este método es un enfoque más simplificado que el uso de cualquiera de los temporizadores en el marco.

Eche un vistazo al siguiente enlace para obtener más información:

Ejecución de un proceso periódico en .NET utilizando un servicio de Windows:
http://allen-conway-dotnet.blogspot.com/2009/12/running-periodic-process-in-net-using.html

atconway
fuente
0

Usamos aplicaciones de consola también. Si utiliza herramientas de registro como Log4net, puede supervisar correctamente su ejecución. Además, no estoy seguro de cómo son más difíciles de mantener que una página web, dado que puede compartir algunas de las mismas bibliotecas de código entre los dos si está diseñado correctamente.

Si está en contra de que esas tareas se ejecuten de manera programada, podría tener una página web en su sección administrativa de su sitio web que actúe como una cola. El usuario realiza una solicitud para ejecutar la tarea, a su vez inserta un registro de sello de fecha en blanco en la tabla MyProcessQueue y su tarea programada verifica cada X minutos un nuevo registro en MyProcessQueue. De esa manera, solo se ejecuta cuando el cliente quiere que se ejecute.

Espero que esas sugerencias ayuden.

Kyle B.
fuente
0

Una opción sería configurar un servicio de Windows y hacer que llame a su tarea programada.

En winforms he usado Timers puesto, no creo que esto funcione bien en ASP.NET

AJM
fuente
-1

Una nueva biblioteca de clases del programador de tareas para .NET

Nota: Desde que se creó esta biblioteca, Microsoft ha introducido un nuevo programador de tareas (Task Scheduler 2.0) para Windows Vista. Esta biblioteca es un contenedor para la interfaz Task Scheduler 1.0, que todavía está disponible en Vista y es compatible con Windows XP, Windows Server 2003 y Windows 2000.

http://www.codeproject.com/KB/cs/tsnewlib.aspx

Ali
fuente
Por favor borrar. Se ha respondido a continuación. Duplicado
Fandango68