2009-12-30 15 views
8

Aquí está el problemaSolución al problema de larga duración consulta en una aplicación web (solicitud asincrónica)

Un usuario de una aplicación web de la empresa está realizando una tarea que resulta en una (muy largo) consulta a la base de largo (o otro procesamiento larga tarea intensiva)

Problemas:

  • solicitud de tiempo de espera - después de un tiempo, el usuario puede obtener una solicitud de tiempo de espera
  • sesión de tiempo de espera - Si no se utilizan métodos de mantenimiento de la sesión, una sec tiempo de espera sión puede ocurrir
  • Solicitud de bloqueo de rosca
    • ya que el hilo de solicitud no está regresando, puede bloquear nuevas requrests (si alcanza el límite de la piscina)
    • En algunos servidores de aplicaciones estado de salud del servidor podría desencadenar una forzada reinicio del nodo o aplicación (debido a una solicitud hilo de larga ejecución)
  • Si el usuario abandona la página:
    • la transacción no se cancela - lo que resulta en el procesamiento inútiles que nadie se beneficiará de
    • el usuario no puede volver a ver los resultados después de completar
  • ninguna indicación de progreso - el usuario simplemente espera a que la página se actualice

Hay varias soluciones que surgieron, pero no estoy seguro de saber qué es mejor (en todos los aspectos, rendimiento, mejores prácticas, elegancia y facilidad de mantenimiento) y me gustaría saber cuál es la solución recomendada, y si existe una solución que me perdí? (Probablemente sí, y muchos)

La mala solución: usar el hilo solicitud como un subproceso de trabajo, guardar el estado de avance en la sesión, tienen un AJAX llamar a comprobar el estado (en la sesión) en otra solicitud paralela

Solución de compromiso: cree su propio grupo de subprocesos, gestione un subproceso de supervisión, un subproceso de trabajo y se encargue de agrupar sincronizando los estados en un caché transaccional distribuido o almacenamiento persistente. esto libera la solicitud, pero crea hilos de los que el servidor de aplicaciones no tiene conocimiento, y no se cerrarán en caso de anulación de la implementación. Depende de ti el apagar los hilos de una manera limpia, y siempre hay una posibilidad de que termines filtrando algo. Esta no es la manera J2EE de hacerlo tampoco.

La solución J2EE: utilizar JMS para la tarea asíncrona, esto es lo que es ment para

la solución Primavera: el uso de Primavera lotes

¿Qué harías/hicieron en sus proyectos? ¿Qué otras soluciones sabes? ¿Cuál de los que anoté anteriormente es el ganador en tu opinión?

Respuesta

13

me gustaría hacer una combinación de su llamada "mala solución" y la "solución J2EE":

  1. El hilo de interfaz de usuario original, envía un mensaje JMS asíncrona al "back-end" y vuelve.
  2. El servidor recibe la solicitud asíncrona y la procesa.
  3. Cuando se alcanza un resultado (o error) en el back-end, se devuelve a la capa del controlador.
  4. La IU, que aún realiza encuestas AJAX o usa Bayeux/Cometed, recibe y muestra el resultado.

El truco es hacer coincidir el par de solicitud/respuesta. Yo lo haría así:

  1. crear un "AsyncManagerService" (AMS) que tiene SESIÓN, tal vez alcance una aplicación uniforme de ancho para todas las discusiones hablan a la misma instancia.
  2. El AMS contiene un mapa con un id como clave y cualquier objeto como valor.
  3. Al crear el mensaje JMS de solicitud, genere una clave aleatoria única y colóquela en el jmsCorrelationId del mensaje, así como en el mapa, con NULL como valor. También pasa esa identificación a la interfaz de usuario.
  4. Deje que la interfaz de usuario muestree el AMS con el ID generado anteriormente , siempre que el valor en el mapa sea NULL.
  5. Cuando el resultado esté listo, deje que su receptor JMS lo coloque en el mapa de AMS con la identificación proporcionada.
  6. La próxima vez que el subproceso de la interfaz de usuario sondee el mapa, recibirá la respuesta y detendrá el sondeo.

Esto es limpio y bien abstraído de cualquier dominio concreto. Una solución puramente técnica.

Incluso si no le gusta el sondeo, HTTP es sin estado por diseño y creo que de esta manera el sondeo solo ocurre en intervalos bien definidos.

De todos modos, he implementado un sistema con exactamente este patrón y funciona muy bien ...

+0

Bien escrito respuesta, gracias –

+0

@Ehrann: ¡Gracias! Implementalo y avísame si tienes una solución más suave ... – raoulsson

1

La solución que he usado anteriormente implica Jetty Cometd en lugar de AJAX.La diferencia principal entre Ajax y Cometd es que Cometd puede usar más de un modelo de pub/sub: el cliente (navegador web en este caso) subscribe al editor (su aplicación) y la aplicación lanza actualizaciones y notificaciones al navegador web como apostado a un modelo ajax de sondeo constante del servidor por el navegador web. Puede utilizar la solución Cometd incluso si no está utilizando embarcadero: puede colocar los contenedores en la carpeta lib de su servidor web respectivo y debería estar listo para comenzar.

0

¿Cuánto duran estas consultas?

Si estás hablando de que las sesiones expiran, tal vez sea mejor para el usuario no estar esperando por ello. Siempre será molesto para el usuario esperar 20 minutos al máximo de vez en cuando en la pestaña de esa consulta.

Por lo tanto, si las consultas son realmente largas, quizás sea mejor cambiar el enfoque de la interfaz de usuario y hacer que el usuario "ordene" una consulta que luego vuelva a ver, o incluso se notifique por correo cuando es Listo.

En tal caso, tendría la consulta preparada en el DB y almacenada en caché, en una tabla separada, allí. Es decir, haría que el servidor web funcionara una vez para registrar la solicitud, tener una tarea de base de datos o un proceso/servidor por separado preparar consultas a petición y notificar al usuario, y luego hacer que el servidor web las muestre cuando el usuario regrese para el resultados.

+0

Esto está cubierto por todas las soluciones sugeridas, obviamente habrá algún proceso de servidor en segundo plano, y alguna notificación al usuario. la pregunta es qué tecnología específica (tecnología Java para ser precisa) es la mejor práctica para usar –

+0

@Ehrann: sugiero que la notificación esté "fuera de línea" si es un tiempo de espera realmente largo, y sugiero que se haga de Trabajo de DB. –

1

muestran un mensaje al usuario que "Su petición es aceptada y tomará una hora de recibir información actualizada"

Crea una tabla que almacena todas estas transacciones y las procesa en un lote en el servidor.

El usuario no tendrá que esperar mucho tiempo y le complacerá ver el mensaje. Puede enviar un correo electrónico de confirmación una vez que se procese la transacción.

Esta es la mejor solución, creo.

Cuestiones relacionadas