Servicio de tareas en segundo plano en un sitio grande

49

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.

¿Me faltan otras objeciones en el proceso de IIS de agrupación de hilos / colas de trabajo?

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?

Kevin Montrose
fuente
La forma correcta es la forma en que cuando decides ir hacia otro lado, miras hacia atrás y dices que deberíamos haberlo hecho de la manera correcta. Elegir sabiamente. Sin embargo, no estoy lo suficientemente familiarizado con IIS world para comentar sobre este problema en particular.
Chris
2
Tengo curiosidad porque tengo un escenario similar (en una escala mucho más pequeña) y también estoy respaldando la conexión desafortunada de algunos usuarios aleatorios. No estoy familiarizado con la mejor solución, así que lo seguiré aquí. :-)
pc1oad1etter
77
No entiendo por qué esto no está en StackOverflow. Esta es una compensación de ingeniería, no una valoración subjetiva. Estás pidiendo un análisis de los diferentes enfoques, todo eso es objetivo. Solo cuando el análisis ha dejado en claro cuáles son exactamente las compensaciones, ¿hay alguna subjetividad y, por lo que puedo ver, su pregunta no es '¿qué debería encontrar más importante, mi tiempo y los recursos del servidor, o el tiempo de mi usuario? ' o algo similar.
Joren
@Kevin Montrose: según sus comentarios, parece que está haciendo una distinción entre "debe hacerse pronto" y "programado en un intervalo". ¿Puede explicar por qué esos son dos tipos diferentes de tareas en segundo plano que requieren un patrón / infraestructura diferente?
Portman el
@Portman: la diferencia fundamental es que las tareas "pronto" no se pueden hacer de forma especulativa, realmente tenemos que esperar hasta saber que hay que hacerlas. Algunos cálculos al dorso del sobre muestran que si tuviéramos que mover las consultas de "Preguntas relacionadas" (solo una de muchas) a una pestaña cron "tonta", tomaría aprox. Una semana de ejecución sólida para resolver todas las preguntas. En general, también nos gustaría que se ejecuten lo antes posible (sin afectar la experiencia del usuario), mientras que nuestras tareas de intervalo se pueden ejecutar con una frecuencia no mayor de una vez en 5 minutos (y normalmente con mucha menos frecuencia).
Kevin Montrose

Respuestas:

17

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):

  1. Puede desarrollar una interfaz de usuario web sobre su servicio (ya que se ejecuta como una aplicación web). Esto es extremadamente útil para ver lo que sucede en tiempo de ejecución.
  2. Su modelo de implementación para sus aplicaciones web funcionará para su aplicación de servicio.
  3. IIS proporciona algunas características interesantes para manejar fallas de aplicaciones (similar en algunos aspectos a un servicio de Windows).
  4. Los desarrolladores web están muy familiarizados con el desarrollo de aplicaciones web (naturalmente), la mayoría no sabe mucho sobre las mejores prácticas al desarrollar un Servicio de Windows.
  5. Proporciona una serie de alternativas para exponer una API para que otras aplicaciones la consuman.

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:

  1. Seguridad . Puede haber un modelo de seguridad diferente para la IU que muestra información sobre los procesos en segundo plano en ejecución. No me gustaría exponer esta interfaz de usuario a nadie más que al equipo de operaciones. Además, la aplicación web puede ejecutarse como un usuario diferente que tiene un conjunto elevado de permisos.
  2. Mantenimiento . Sería genial poder implementar cambios en la aplicación que aloja los procesos en segundo plano sin afectar al usuario que usa el sitio web front-end.
  3. Rendimiento . Tener la aplicación separada del sitio principal que procesa las solicitudes de los usuarios significa que los subprocesos en segundo plano no disminuirán la capacidad de IIS para manejar la cola de solicitudes entrantes. Además, la aplicación que procesa las tareas en segundo plano podría implementarse en un servidor separado si es necesario.

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.

Rohland
fuente
La idea básica de usar un sitio web separado como servicio es intrigante y no la había considerado ...
Kevin Montrose
Rohland, puede que me falte algo aquí, pero parece que estás diciendo que estabas interactuando con un servicio de Windows desde el controlador NServiceBus, el servicio luego envía el correo electrónico. Si estoy en lo cierto, ¿puedo preguntarle por qué simplemente no envía el correo electrónico desde un controlador de mensajes NServiceBus, que sería muy fácil de desarrollar, probar e implementar?
Sean Kearon
El sitio web envía un mensaje al Servicio de Windows. El controlador de mensajes NServiceBus de Windows Service recoge el mensaje y lo envía. En esencia, eso es lo mismo que el proceso que se describe.
Rohland
22

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 CRONtrabajo que ejecuta una parte de su infraestructura. En Windows, esto se conoce como task schedulery 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/

Nick Berardi
fuente
2
Hago esto con mi servicio de alojamiento compartido ya que no tengo acceso de shell. Escriba una página PHP que haga algo importante, y luego tenga un trabajo cron que cargue la página usando wget o lynx periódicamente. Esto suena exactamente como el tipo de cosa que funcionaría en este caso y sería extremadamente simple, sin apenas requerir un cambio en la forma en que se hacen las cosas actualmente.
Ricket
Qué solución tan simple. Ha generado ideas para mi propio proyecto que ni siquiera estaba considerando. Además, tiene acceso completo a su base de código existente. Simplemente agregue un proyecto de consola a la solución y haga referencia a los proyectos existentes.
Tim Murphy
10

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:

  1. Cree un controlador / acción en su aplicación web para manejar tareas programadas en segundo plano. Por convención, suelo llamar al mío http://mydomain.com/system/cron.
  2. Por seguridad, esta acción debe bloquearse solo para direcciones IP autenticadas en la red local.
  3. En una máquina separada, instale Wget y configure una tarea programada para que wget obtenga el recurso del paso 1. Puede hacer que la tarea se ejecute con la frecuencia que desee (generalmente opto por 30 segundos). No olvide pasar el argumento de cookies apropiado a Wget para que se autentique en su aplicación web.
  4. Por redundancia, también puede instalar un segundo wget programado en una segunda máquina.

¡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 cronacció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

Pros
  • Ya eres muy bueno escribiendo código ASP.NET MVC, por lo que te permite escribir tus tareas en segundo plano en la misma plataforma en la que escribes el resto de tu solución.
  • Las tareas se ejecutan en el mismo contexto que su aplicación web, por lo que puede compartir la memoria caché y utilizar métodos auxiliares que ya existen.
  • Si tiene que buscar un URI con equilibrio de carga , sus tareas en segundo plano ahora también tienen equilibrio de carga.
  • Implementación simultánea : no tiene que preocuparse por sincronizar su aplicación web con su lógica de tareas en segundo plano, porque todas están en la misma implementación.
Contras
  • A lo largo de los años, algunas personas me han dicho que este diseño está "muy acoplado", pero cuando se les presionó no han podido expresar por qué eso es algo malo.

Nota: Si tiene alguna pregunta o inquietud, agregue un comentario . Estoy feliz de elaborar.

Portman
fuente
7

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.

James Avery
fuente
6

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 un Perform()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.

Ben Scheirman
fuente
Serializar los parámetros relevantes no es realmente un "justo", es casi el "todo". Es una de mis mayores reservas sobre el enfoque de proceso separado ...
Kevin Montrose
Sí, esa es la misma solución que utilicé, sin embargo, serialicé todo el objeto en la base de datos como un binario y luego los saqué para ejecutarlos. Usé Cassandra como mi almacenamiento persistente y el Programador de tareas como mi programador CRON para la aplicación de línea de comandos que ejecutaría y ejecutaría las tareas.
Nick Berardi
Comenzamos simplemente incluyendo una simple pieza de datos en el mensaje y terminando arrojando todo el objeto. Todavía funcionó muy bien. Consideraría la separación ya que también tiene otros beneficios.
Nathan Palmer
@ Kevin - aunque sólo tuvimos algunas personas con mucha historia serialización ....
Marc Gravell
4

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

bus.Send(new ProjectApproved()); // returns immediately

El servicio de Windows recibe y procesa mensajes en su propio tiempo

public class DoesSomethingAwesome : ConsumerOf<ProjectApproved>
{
   public void Consume(ProjectApproved Message)
   {
      // Do something "offline"
   }
}

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

// Save your object
store.Save(completeProject);

// Send a message indicating its ready to be processed
bus.Send(new ProjectApproved() { ProjectId = completeProject.Id });

El servicio de Windows recibe y procesa mensajes en su propio tiempo

public class DoesSomethingAwesome : ConsumerOf<ProjectApproved>
{
   public void Consume(ProjectApproved Message)
   {
      // Retrieve your object back
      var completeProject = store.Get(Message.ProjectId);
   }
}

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.

Nathan Palmer
fuente
De todos modos, usar un bus de servicio con CQRS siempre es una buena manera de mejorar su escalabilidad
piense antes de codificar el
3

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.

#!/bin/bash
wget -O /dev/null http://stackoverflow.com/specially_crafted_url

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í:

wget -O /dev/null http://localhost/specially_crafted_url

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.

suave
fuente
Ya lo hacemos para todo lo que se ejecuta a intervalos predecibles, lo que nos queda son cosas que no se pueden predecir con demasiada anticipación. Por ejemplo, el "bloque de preguntas relacionadas" solo se actualiza en las preguntas que se han visto recientemente. Las listas de preguntas etiquetadas del mismo modo solo se almacenan en caché si a alguien le importa verificar esas etiquetas. Como tenemos más de un millón de preguntas y nos acercamos a las etiquetas de 25k, no podemos ejecutar todas las tareas asociadas (y eso es solo 2 ejemplos) "por si acaso".
Kevin Montrose
También hay problemas de equilibrio de carga, ya que SO se divide en varios servidores. Básicamente, si va a stackoverflow.com, siempre encontrará el mismo servidor. El enfoque wget nos obligaría a ordenar todas las tareas en un solo servidor (o realmente reelaborar nuestra configuración de equilibrio de carga), lo que sería realmente doloroso.
Kevin Montrose
Sé amable si las cosas funcionaran a intervalos regulares, ¿eh? Entiendo lo que estás diciendo, pero la metodología descrita anteriormente (y creo que mencionada por algunas otras personas) no cambia. Cuando las vistas de una página dicen "es hora de ejecutar este trabajo", pegas el trabajo en una cola de mensajes. Un trabajo en segundo plano de larga ejecución ejecuta los trabajos que encuentra. En este caso, los trabajos no son más que URL que deben solicitarse. jeje Probablemente podría configurar esto en un servidor compartido de $ 20 al mes, ya que no necesita su base de código para ejecutarse. Eche un vistazo a Amazon SQS para obtener un servicio de mensajería fácil de usar.
mellowsoon
En cuanto a los problemas de equilibrio de carga. ¡Donde hay voluntad hay un camino! En lugar de realizar la solicitud a stackoverflow.com, puede acceder a un servidor al azar utilizando su dirección IP. Si el equilibrador de carga comprueba las cookies en las solicitudes de canalización, puede falsificar las cookies. Si verifica la dirección IP, probablemente podría fingir eso (ya que no le importa la respuesta del servidor).
mellowsoon
Acordó que el equilibrio de carga no debería ser una razón para no hacer esto. Dado que la solicitud specially_crafted_urlproviene 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.
Portman el
2

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:

  1. Cree una cola de trabajos (ya sea en memoria o DB, sea cual sea la persistencia necesaria para los tipos de trabajos)
  2. Cree un servicio web que ejecute los trabajos en cola
  3. La aplicación de servicio simple que llama al servicio web en un intervalo específico, deja todas las cosas complejas (recuperación y ejecución de trabajos) para el servicio web en su base de código central.

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".

Brandon
fuente
1
Tengo exactamente esto en una aplicación importante en el trabajo: un servicio de Windows que activa la aplicación web a intervalos. La aplicación web permanece sin estado, extrayendo el estado de la base de datos según sea necesario. Funciona de maravilla.
Bevan
1

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/

Shane
fuente
1

¿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.

Rob Sobers
fuente
1

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:

  • No hay servicio externo para monitorear
  • Simplicidad de implementación: sin cálculo de procesos cruzados, sin supervisión avanzada
  • Todavía está dentro de su proceso de IIS, por lo que puede hacer todo su registro habitual y así sucesivamente (sin necesidad de múltiples archivos de registro)
  • Implementación enormemente simplificada (cuando actualiza un servicio, debe detener el servicio, copiar los archivos, iniciar el servicio; esto se suma a sus actualizaciones habituales del código del sitio web)

En mi opinión, una solución en IIS es simplemente el "siguiente paso" de llevar el trabajo a vistas de páginas aleatorias.

Dean Harding
fuente
1

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

Lukas
fuente
¡Debo probar Kthxbye aunque solo sea por el gran nombre!
Nathan Palmer
más o menos lo asombroso. el próximo será el ORLY? biblioteca. probablemente para el monitoreo de estadísticas de algún tipo ...;)
Lukas
0

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

  • MSMQ (no está muerto ... todavía)

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
0

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.

John Christensen
fuente
0

Puede derivar el trabajo en un subproceso de fondo (o muchos subprocesos de fondo) utilizando Rx y algo como lo siguiente:

var scheduler = new EventLoopScheduler( SchedulerThreadName );
_workToDo = new Subject<Action>();
var queueSubscription = _workToDo.ObserveOn( scheduler ).Subscribe( work => work() );
_cleanup = new CompositeDisposable( queueSubscription, scheduler );

Usar:

var work = () => { ... };
_workToDo.OnNext( work ); // Can also put on error / on complete in here

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).

Neal
fuente
0

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.

Christopher Mahan
fuente
0

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 .

Spolsky: Me di cuenta de que una de las preguntas que hizo en el blog fue cómo debe manejar las tareas recurrentes de mantenimiento en general.

Atwood: si.

Spolsky: ¿Es una caracterización justa? Cada sitio web tiene algunas tareas que no desea ejecutar en el momento en que se carga una página web, pero desea ejecutar con algún tipo de recurrencia.

Atwood: Sí, tareas en segundo plano.

Spolsky: Sí, ¿qué descubriste?

Atwood: Bueno, originalmente pregunté en Twitter, porque solo quería algo ligero. Realmente no quería escribir un servicio de Windows. Sentí que eso estaba fuera del código de la banda. Además, el código que realmente hace el trabajo es una página web, porque para mí esa es una unidad lógica de trabajo en un sitio web es una página web. Entonces, realmente es como si volviéramos a llamar al sitio web, es como otra solicitud en el sitio web, así que lo vi como algo que debería mantenerse en línea, y el pequeño enfoque que surgió que me recomendaron en Twitter esencialmente era agregar algo al caché de la aplicación con una caducidad fija, luego tiene una devolución de llamada para que cuando caduque llame a una determinada función que hace el trabajo y luego lo agregue nuevamente al caché con la misma caducidad.

Pensamiento extraño
fuente
1
Sí, eso funciona para sitios mucho más pequeños de lo que se ha convertido StackOverflow. La escala es un gran problema aquí, desafortunadamente (o afortunadamente, dependiendo de cómo se mire).
Kevin Montrose
@Kevin Montrose, declaro ignorancia completa del dominio aquí. ¿Podría explicar por qué tener una (s) página (s) secreta (s) realiza (n) en el trabajo (quizás en unidades pequeñas) y ser llamado por un trabajo de actualización de página / cron en otro lugar no es escalable? No dudo que tengas razón, pero me encantaría aprender.
Pensamiento extraño
su sugerencia particular (la caducidad de la memoria caché) no escala porque todas las caducidades de la memoria caché (en ASP.NET) ejecutan un solo hilo (es un truco inteligente para sitios más pequeños, como solía ser SO). Una tarea cron no escala porque hemos superado un solo servidor (SO ahora es 3 y sigue creciendo) y cualquier tarea cron estaría afectando a un solo servidor (al menos, cambiar ese invariante sería realmente doloroso con nuestra carga) configuración de equilibrio). Una tarea cron también tendría que ejecutarse con mucha frecuencia, ya que estas tareas son recurrentes en el orden de los minutos.
Kevin Montrose
Vale la pena señalar que sí usamos la programación de "estilo cron" para ejecuciones menos frecuentes, intervalos fijos, tareas ya, cosas como concesión de credenciales y avisos diarios por correo electrónico.
Kevin Montrose
0

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:

  • Una carga útil de datos que parametriza la tarea.
  • Código que implementa la tarea.

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.

antony.trupe
fuente
No sugiero usar la API de cola de tareas GAE, sino seguir su modelo. Lo han pensado durante un tiempo y han escrito una implementación.
antony.trupe
0

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.

Cuenta
fuente