Estamos lidiando con un problema interesante en StackOverflow.
Tenemos un montón de pequeñas tareas "que hay que hacer pronto". Un ejemplo es actualizar las listas de "Preguntas relacionadas". Lo que hemos hecho en el pasado es incluir esas tareas en las cargas de página de algunos usuarios.
Esto nunca fue ideal, pero no fue realmente notable. Ahora que SO ha pasado el signo de interrogación de 1,000,000, esos usuarios desafortunados están comenzando a sentirlo.
La solución natural es llevar estas tareas a un segundo plano. Estoy considerando dos formas generales de hacerlo.
1. En IIS como Thread-Pool / Work-Queue personalizado
Básicamente, hacemos girar algunos subprocesos (que no son ThreadPool , para no interferir con IIS) y hacer que brinden servicios a algunas colecciones en las que estamos insertando Funcs .
El gran profesional aquí es la simplicidad. No tenemos que preocuparnos por ordenar nada, ni debemos asegurarnos de que algún servicio externo esté funcionando y responda.
También tenemos acceso a todo nuestro código común.
La desventaja es, bueno, que no debemos usar hilos de fondo. Las objeciones que conozco se centran en IIS muerto de hambre (si usa ThreadPool) y los hilos que mueren al azar (debido al reciclaje de AppPool).
Tenemos la infraestructura existente para hacer que la muerte aleatoria de subprocesos no sea un problema (es posible detectar que una tarea ha sido abandonada, básicamente), y limitar el número de subprocesos (y usar subprocesos que no sean ThreadPool) tampoco es difícil.
Movido a StackOverflow , ya que no se abordó realmente aquí.
2. Como un servicio
Ya sea alguna solución de terceros o personalizada.
Básicamente, ordenaríamos una tarea a través del límite del proceso para algún servicio y simplemente nos olvidaríamos de ella. Presumiblemente, estamos vinculando algún código o restringido a SQL sin formato + una cadena de conexión.
La ventaja es que es la "forma correcta" de hacer esto.
Las desventajas son que estamos muy restringidos en lo que podemos hacer, o tendremos que resolver algún sistema para mantener este servicio sincronizado con nuestra base de código. También tendremos que conectar todo nuestro monitoreo y registro de errores de alguna manera, que obtenemos de forma gratuita con la opción "En IIS".
¿Hay otros beneficios o problemas con el enfoque de servicio?
En pocas palabras, ¿hay problemas imprevistos e insuperables que hacen que el enfoque n. ° 1 sea inviable y, de ser así, hay algún buen servicio de terceros que deberíamos considerar para el enfoque n. ° 2?
fuente
Respuestas:
Hace unas semanas hice una pregunta similar sobre SO. En pocas palabras, mi enfoque durante algún tiempo ha sido desarrollar un Servicio de Windows. Usaría NServiceBus (esencialmente MSMQ debajo de las cubiertas) para reunir las solicitudes de mi aplicación web a mi servicio. Solía usar WCF, pero hacer que una transacción distribuida funcionara correctamente sobre WCF siempre parecía una molestia. NServiceBus hizo el truco, pude confirmar datos y crear tareas en una transacción y no preocuparme si mi servicio estaba funcionando en ese momento. Como ejemplo simple, si alguna vez necesito enviar un correo electrónico (por ejemplo, un correo electrónico de registro) crearía la cuenta de usuario y dispararía una señal a mi Servicio de Windows (para enviar el correo electrónico) en una transacción. El manejador de mensajes en el lado del servicio recogerá el mensaje y lo procesará en consecuencia.
Desde que se lanzó ASP .NET 4.0 y AppFabric, existen varias alternativas viables al mecanismo anterior. Volviendo a la pregunta que mencioné anteriormente, ahora tenemos AppInitialize de AppFabric (a través de net.pipe), así como la característica de inicio automático de ASP .NET 4.0 que hace que el desarrollo de los Servicios de Windows como aplicaciones web sea una alternativa viable. He comenzado a hacer esto ahora por varias razones (la mayor de ellas es la implementación ya no es una molestia):
Si sigues esta ruta (perdóname por copiar y pegar desde mi publicación original) definitivamente consideraría ejecutar la lógica de fondo en una aplicación web separada. Hay varias razones para esto:
Hacer esto vuelve al aspecto de clasificación. WCF, NServiceBus / RabbitMQ / ActiveMQ etc., vanilla MSMQ, RESTful API (piense en MVC) son todas las opciones. Si está utilizando Windows Workflow 4.0, podría exponer un punto final de host que su aplicación web podría consumir.
El enfoque de alojamiento web para los servicios todavía es bastante nuevo para mí, solo el tiempo dirá si fue la elección correcta. Hasta ahora todo bien. Por cierto, si no quieres usar AppFabric (no pude porque por alguna extraña razón, Windows Server Web Edition no es compatible), la capacidad de inicio automático mencionada en la publicación del Gu funciona muy bien. Sin embargo, manténgase alejado del archivo applicationhost.config, todo en esa publicación es posible configurar a través de la consola IIS (Editor de configuración en el nivel del servidor principal).
Nota: Originalmente había publicado algunos enlaces más en este mensaje, pero, por desgracia, esta es mi primera publicación en este intercambio y solo se admite un enlace. Básicamente, había otros dos, para obtener Google "Death to Windows Services ... Long Live AppFabric!" y "auto-start-asp-net-aplicaciones". Lo siento por eso.
fuente
En realidad, hay una tercera forma en Windows para ejecutar servicios en segundo plano, y es muy común en el mundo UNIX. La tercera forma es un
CRON
trabajo que ejecuta una parte de su infraestructura. En Windows, esto se conoce comotask scheduler
y es muy común para ejecutar código de forma programada. Para usar esto, crearía una aplicación de línea de comandos que se ejecuta en un horario predefinido. La ventaja de esto es que no tiene que preocuparse si el proceso sigue funcionando como un servicio, porque si falla por alguna razón, la próxima vez comenzará.En cuanto a la organización de tareas específicas, realmente solo necesita almacenar estas tareas en un almacenamiento binario persistente. Hasta que la aplicación de línea de comando los saque del almacenamiento y los ejecute. He hecho esto en el pasado usando la base de datos Cassandra como un proveedor de estado de sesión para rellenar tareas en segundo plano para usuarios específicos en la base de datos Cassandra, y luego hacer que la línea de comandos los seleccione y los ejecute para el usuario.
Puede que esta no haya sido la solución típica de clasificación, pero funcionó muy bien para mí y resultó ser una solución muy elegante, porque las tareas programadas sobrevivieron a paradas, problemas de red y cualquier máquina podía ejecutar la tarea ya que era central almacenado
Promoción descarada, pero este es mi proyecto y la solución que acabo de detallar brevemente es por qué creé el proyecto: http://github.com/managedfusion/fluentcassandra/
fuente
Aplicación web Cron +
Este es un diseño probado en batalla que se escala horizontalmente junto con su granja web y garantiza que esté utilizando la pila de tecnología web que ya conoce.
Así es como funciona:
http://mydomain.com/system/cron
.¡Hurra! Ahora tiene una ruta que se llamará cada 30 segundos. Y si la solicitud tarda 5 minutos en procesarse, a nadie le importará, porque no es parte de la solicitud de la página de un usuario.
La
cron
acción termina pareciendo muy simple: tiene una lista de métodos para ejecutar en una determinada frecuencia. Cuando llega una solicitud, ve si hay un método que debe ejecutarse y llama al método apropiado. Esto significa que puede controlar la programación en su base de datos , donde probablemente ya tenga muchos otros datos de configuración importantes para su sitio.Más importante aún (para usted), esto significa que sus trabajos no tienen que ser llamados en un horario fijo. Puede escribir cualquier lógica que desee para determinar cuándo ejecutar un método.
Pros y contras
ProsNota: Si tiene alguna pregunta o inquietud, agregue un comentario . Estoy feliz de elaborar.
fuente
He intentado y utilizado casi todas las formas posibles de hacerlo en mi aplicación actual. Comencé haciendo lo mismo que usted actualmente, aprovechando una solicitud del usuario para completar los datos y luego almacenarlos en caché en el futuro. Me di cuenta de que esto también era una mala idea (especialmente cuando escalas a varios servidores web, más usuarios reciben el golpe).
También he tenido un trabajo programado que llega a una URL en la aplicación ASP.NET; esta es una solución decente, pero comienza a desglosarse en el momento en que escalas más allá de 1 servidor web.
Actualmente uso dos métodos diferentes, ambos usando Quartz.NET, que es una pequeña biblioteca genial. El primero es Quartz.NET que se ejecuta en proceso con ASP.NET, se configura en global.asax y se ejecuta cada dos minutos. Lo uso para actualizar el caché ASP.NET fuera de banda, que es la única razón por la que se ejecuta como parte de ASP.NET.
El segundo es que escribí una biblioteca para envolver Quartz.NET llamada DaemonMaster: hace que sea fácil colocar una DLL en un directorio y ejecutarla en un servicio de Windows. Descubrí que ayuda a evitar algunas de las partes molestas de trabajar con un servicio de Windows y también limpia la API de Quartz.NET. Los servicios que se ejecutan a través de DaemonMaster son de dos tipos diferentes, el primero son trabajos que deben ejecutarse todas las noches o cada X minutos. Los otros trabajos funcionan fuera de una cola en función de los datos provenientes de la aplicación ASP.NET. La aplicación ASP.NET coloca objetos JSON en RabbitMQ y los servicios sondean RabbitMQ y luego procesan los datos.
En base a esto, sugeriría que vaya con un servicio de Windows (y consulte DaemonMaster) y, si es necesario, use una cola como RabbitMQ para pasar los datos de la aplicación ASP.NET a los servicios: ha funcionado mejor con todas estas soluciones . Si está cargando caché, entonces ejecutar en ASP.NET tiene sentido, de lo contrario no creo que lo haga.
fuente
Lo haría de la manera correcta y tendría un servicio de Windows en ejecución que monitorea una "cola". Digo "cola" porque la programación con MSMQ es similar a pegar hot pokers en los globos oculares.
Me enamoré de la simplicidad de Delayed :: Job in Rails, y algo similar podría hacerse fácilmente en .NET.
Básicamente agrega cualquier tipo de
SomethingOperation
(algo que tiene unPerform()
método). Luego, solo serialice los parámetros relevantes, dele prioridad, algún tipo de comportamiento de reintento predeterminado y colóquelo en una base de datos.Su servicio solo supervisaría esto y trabajaría los trabajos en la cola.
fuente
Estamos muy contentos con un enfoque de Service Bus / Message Queue / Service. La arquitectura básica es esta.
El sitio web envía un mensaje a la cola
El servicio de Windows recibe y procesa mensajes en su propio tiempo
La ventaja es que no hay demora para el servicio front-end que los usuarios también están conectados. El servicio de Windows se puede cerrar y actualizar sin interrupción al sitio principal. Además, es extremadamente rápido .
Si no puede almacenar todos sus datos dentro del mensaje, siempre puede almacenarlos y recuperarlos más tarde. Sugiero usar un mecanismo de almacenamiento de documentos como: RavenDB o MongoDB, donde es muy sencillo almacenar sus clases sin cambios.
El sitio web envía un mensaje a la cola
El servicio de Windows recibe y procesa mensajes en su propio tiempo
Para simplificar las cosas, utilizamos: Rhino ESB y Topshelf . La configuración es extremadamente simple y poner esto en práctica para una aplicación existente ha demostrado tomar muy poco tiempo.
fuente
Tengo curiosidad por qué una combinación de los dos no es una opción viable. En este momento, desencadena trabajos en las vistas de página, con un poco de mala suerte atascado esperando 10 segundos para que aparezca la página. Al menos esa es mi comprensión de su método actual.
Sin embargo, esos trabajos están tardando más y más en ejecutarse a medida que el sitio crece, y no desea descarrilar la experiencia del usuario en el sitio. Ni siquiera para unos pocos (o quizás muchos) usuarios desafortunados durante todo el día, por lo que ahora está pensando en programar trabajos en segundo plano.
No veo por qué un trabajo en segundo plano ejecutado a intervalos regulares no puede imitar a un visitante. Ahora no soy un programador de Windows, pero en el mundo de Linux configuraría un trabajo cron que se ejecuta en un intervalo regular, y tendría 2 líneas de código.
Combina las ventajas de ambos sistemas. Está hecho en el fondo. No afecta a los usuarios. Todavía usa una vista de página para iniciar el trabajo. He visto este enfoque usado antes. Tiende a ser el punto medio entre las formas simples de antaño y las formas más complejas que vienen por el camino.
Actualizar
Creo que puede solucionar el problema del equilibrio de carga ejecutando los corredores de trabajo en los propios servidores web. El corredor de trabajos extrae una URL de la cola de trabajos y la ejecuta así:
Debido a la naturaleza de las colas de trabajo / mensajería, los trabajos se distribuirán de manera uniforme entre los corredores de trabajo, lo que significa que el special_crafted_url finalmente se distribuye entre sus servidores web.
fuente
specially_crafted_url
proviene de una IP conocida, puede agregar una regla en su equilibrador de carga para hacer una operación por turnos solo para solicitudes de esa IP.Creo que la desventaja con el enfoque de servicio puro es que tiene código disperso en el servicio y fuera de la aplicación principal.
Esto es lo que hemos hecho con grandes trabajos en segundo plano no sensibles al tiempo, que mantiene el código unido y simplifica el servicio:
Aún más simple, simplemente realice la llamada en una aplicación de consola y use el Programador de tareas o VisualCron para convertirlo en un "servicio".
fuente
Me gustó TopShelf. Mantiene la simplicidad y, sin embargo, lo hace de la manera correcta como un servicio de Windows Básicamente, cree una aplicación de consola, agregue aproximadamente 15-20 líneas de código, luego se instala como un servicio.
http://code.google.com/p/topshelf/
fuente
¿Qué tal tener un servicio de Windows muy simple que se ejecute en el servidor web y periódicamente acceda a una URL de mantenimiento que realice sus tareas diversas? Haga que acelere la cantidad de trabajo que realiza en una solicitud determinada.
fuente
Voy a contrarrestar la tendencia aparente aquí y sugeriría ir al modelo en IIS. Lo he usado yo mismo y funciona muy bien. Realmente no es tan difícil implementar una clase de grupo de subprocesos decente (a lo largo de los años, he ampliado mi clase de grupo de subprocesos para admitir la creación dinámica y la destrucción de subprocesos, reintentos de trabajos, etc.). Las ventajas son:
En mi opinión, una solución en IIS es simplemente el "siguiente paso" de llevar el trabajo a vistas de páginas aleatorias.
fuente
Resque es bueno. O incluso Kthxbye si necesita que se le notifique el valor resultante una vez que se haya completado.
Ambos basados en Redis / Ruby.
Honestamente, si está haciendo un enfoque basado en el servicio, realmente no necesita estar súper integrado con su plataforma actual, lo que creo que es una ventaja. Espero que sea un sistema de configurar y olvidar que se ejecute (con algún tipo de monitoreo) y complete los trabajos. No estoy seguro de que deba ejecutarse en la misma plataforma, ya que solo actualiza / modifica la información de la base de datos.
Estoy bastante seguro de que podría salirse con la suya con mucho más por mucho menos si cultivara este tipo de trabajo en una entidad separada, especialmente porque parece que está lidiando con problemas de subprocesos. Tanto Resque como Kthxbye mueven el procesamiento a procesos separados para permitir que el SO maneje la concurrencia.
Resque
Kthxbye
fuente
Usaría un servicio WCF alojado WAS escuchando una cola MSMQ.
Pro
Dispara y olvida mensajes unidireccionales desde la aplicación web
MSMQ / WCF aceleración y reintento
Entrega garantizada; D
Gestión de letra muerta
Procesamiento distribuido
Activación WAS / MSMQ
Contras
Las características de MSMQ en WCF hacen que usar MSMQ sea realmente agradable. Sí, sangrará en la configuración, pero los beneficios superarán el sacrificio.
fuente
Me he encontrado con esto un par de veces al desarrollar aplicaciones web. Lo hemos resuelto creando una aplicación de consola de Windows que lleva a cabo la tarea, y creando una tarea programada que se ejecuta de vez en cuando para realizar la tarea.
fuente
Puede derivar el trabajo en un subproceso de fondo (o muchos subprocesos de fondo) utilizando Rx y algo como lo siguiente:
Usar:
Organice todo eso dentro de una clase de la que solo haya uno (también conocido como singleton, pero hágalo correctamente; use su contenedor IoC para determinar el estilo de vida).
Puede controlar el tamaño del grupo de subprocesos, etc. escribiendo un planificador personalizado en lugar de usar EventLoopScheduler (que ejecuta un solo subproceso).
fuente
He implementado este tipo de cosas varias veces. En Windows, configuré un programa de línea de comandos de Python que hace algo en varias ocasiones. Este programa también expone una interfaz xmlrpc en un puerto. Luego, un trabajo de tarea programada se ejecuta cada minuto y consulta las interfaces xmlrpc. Si no están arriba, intenta lanzarlos. Si no puede, me envía un correo electrónico.
La ventaja es que el trabajo que se ejecuta no es cron o está programado. Tengo un trabajo de proceso que se ejecuta cada segundo, pero esperará cada vez más entre comenzar un nuevo trabajo dependiendo de si tenía trabajo que hacer. Además, se puede utilizar para actuar de forma inteligente en función del resultado. ¿Tienes un error 500? ¿Tienes un retraso muy largo? Hacer algo más. Notificar a otro servicio. Etc.
Y el mismo sistema funciona en Unix, con modificaciones menores.
fuente
No tengo una respuesta para ti, pero el problema hizo sonar una campana: recuerdo a algunos tipos al azar que lo discutieron en un podcast una vez .
fuente
Descripción general de la API de Java de Task Queue
Conceptos de tareas
En el procesamiento en segundo plano de App Engine, una tarea es una descripción completa de una pequeña unidad de trabajo. Esta descripción consta de dos partes:
Tareas como Web Hooks sin conexión
Afortunadamente, Internet ya ofrece una solución de este tipo, en forma de una solicitud HTTP y su respuesta. La carga útil de datos es el contenido de la solicitud HTTP, como las variables de formulario web, XML, JSON o datos binarios codificados. La referencia del código es la URL misma; el código real es cualquier lógica que ejecute el servidor al preparar la respuesta.
fuente
Haz ambos
Agregue un parámetro opcional a la ruta de la pregunta que hace el trabajo que actualmente está aprovechando las solicitudes de los usuarios:
Servicio de tareas en segundo plano en un sitio grande
Cree una aplicación de consola que se ejecute en cada servidor y abra el registro binario compartido de IIS y lo lea hasta el final actual del archivo. Use un observador del sistema de archivos o un intervalo de tiempo para leer hacia adelante para recopilar actualizaciones a medida que IIS vació el registro.
Use esta información para determinar qué páginas se han visto actualmente.
Use las URL de la página del registro analizado para llamar a la versión "extrastuff" de la url en localhost con un objeto de cliente web.
Agregue algún código para cambiar los archivos al final de cada período de registro o reinicie el proceso cada período de registro.
fuente