¿Patrón para solicitudes con largos tiempos de respuesta?

7

Actualmente estamos manteniendo un "servidor web" de Python de cosecha propia, en el que generar la respuesta para algunas solicitudes puede llevar mucho tiempo, principalmente debido a cálculos pesados: estas solicitudes son básicamente publicaciones con tiempos de espera muy largos (piense minutos a decenas de minutos).

Un problema de esta arquitectura es que a veces existe la necesidad de cancelar dicha solicitud, por ejemplo, el usuario notó un error al configurar la solicitud. Actualmente, la cancelación es otra solicitud, que cancela la solicitud de larga ejecución, pero hay muchas lagunas, por ejemplo, ¿qué sucede si el cliente simplemente cierra el sitio web?

Actualmente, estamos planeando retirar la abominación local de un servidor web y cambiar a algo sensato, por ejemplo, Flask ejecutándose dentro de un IIS usando wfastcgi. Debido a razones políticas, IIS está configurado, por lo que cambiar a algo como gunicorn está fuera de la ventana.

Todo el desarrollo se ha estancado en eso porque nadie tiene una idea de cómo matar los procesos ejecutados por (w) fastcgi; esa preocupación simplemente no es parte de la especificación fastcgi.

Mi sensación es que un intento de construir algo que incorpora eso es un error: preferiría una solución en la que el servidor simplemente descargue esas tareas intensivas de computación a algún servidor en segundo plano (¿matraz + apio?) Y las encuestas de front-end para eso.

Desafortunadamente, la antigua solución estuvo en vigencia durante tanto tiempo que algunos desarrolladores quieren retener el comportamiento a toda costa.

Al no ser un servidor web, me gustaría obtener algunos consejos / patrones sobre cómo podrían ser las soluciones sensatas para tal problema.

Christian Sauer
fuente

Respuestas:

8

Lo que estás sugiriendo es bastante correcto.

Debería ser asíncrono.

Puede publicar una solicitud y la solicitud le proporciona un ID único. Publica un Hecho en esta identificación única en alguna tienda donde puede sondear.

Si necesita cancelar una solicitud, se debe publicar una solicitud de cancelación con el mismo ID.

También en el back-end donde se ejecutan estos cálculos, por ejemplo, en una interfaz de ejecución de un Thread (estilo java), puede verificar cada pocos segundos si el proceso se cancela verificando si se ha solicitado una publicación de cancelación. Si es así, entonces el hilo debe salir. Esta es una salida limpia. También podría usar una interrupción al hilo.

Alumno_101
fuente
En mi humilde opinión, esta solución es la que mejor se adapta al enfoque 'sin estado' que se adapta tan bien a Http: separa el acto de hacer el cálculo de la comunicación de solicitud / respuesta. En este patrón, la comunicación de solicitud / respuesta se convierte en una conversación como esta: 'por favor comienza ... está bien, lo haré ... ¿cómo te va? ... sigue trabajando ... cancela ... está bien, estoy cancelando ... ¿cómo te va? ... el cálculo fue cancelado ... por favor comienza ... (espera) ... ¿cómo te va? .. el cálculo completado aquí son los resultados ".
Robert
2

Te sugiero que busques en wsgi y uses multihilo . Puede administrar cada solicitud en un hilo e implementar tiempos de espera en el hilo. También debería poder administrar los hilos y cancelar solicitudes más fácilmente.

Tereus Scott
fuente
1

El problema que enfrenta actualmente con una simple publicación HTTP simplemente no se puede resolver en ese protocolo. HTTP funciona de forma asíncrona en un cliente / servidor estricto, por lo que no hay notificación del lado del servidor y no hay cancelación nativa. Además, enfrentará el problema de las respuestas perdidas debido a los tiempos de espera de la red de Internet. Sugeriré un enfoque diferente y moderno. Descargo de responsabilidad: un poco menos del 90% de soporte del navegador

Te sugiero que inviertas el flujo de información y uses websockets. Lo que debe hacer una vez que se realiza una tarea es notificar a su usuario y enviar una notificación del servidor al cliente.

Cuando se publica una tarea o, más exactamente, como un reemplazo para la publicación, abra un websocket (use la tecnología de servidor que desee, tornado, gevent, python-websocket, etc.). Asociar el hilo de la tarea en el evento abierto del servidor websocket. Si el cliente se cierra, el cliente enviará un evento cercano a su controlador websocket, para que pueda terminar el hilo asociado con él. De lo contrario, si su tarea finaliza normalmente, el servidor puede enviar los datos al cliente y cerrar el websocket. Además, debe hacer que el servidor haga ping una vez cada 30 segundos porque los websockets se cierran si están inactivos durante más de un minuto.

Si aplica esto, será más rápido y limpio que un sondeo del lado del cliente, mientras resuelve problemas de brecha ya que tiene un canal bidireccional real. Tenga en cuenta que puede implementar servicios adicionales sobre el esquema de tareas, como sesiones, pings de progresión, etc.

Arthur Havlicek
fuente
0

Si su tarea necesita tanto tiempo para realizarse, no lo haga en esa solicitud. Póngalo en cola y realice otro proceso que hará el trabajo.

Una vez realizado el trabajo, simplemente envíe una notificación al usuario de que se ha realizado la "operación x", mientras tanto, muestre el mensaje "su trabajo se realizará en aproximadamente x minutos".

Djuro
fuente