starwars - API REST de larga ejecución con colas
rest api query (1)
Supongo que su sistema se parece a lo siguiente. Usted tiene un servicio REST, que recibe solicitudes del cliente. Convierte las solicitudes en comandos que la lógica empresarial puede comprender. Pones estos comandos en una cola. Tiene un único o varios trabajadores que pueden procesar y eliminar estos comandos de la cola y enviar los resultados al servicio REST, que puede responder al cliente.
Su problema es que debido a sus tareas de larga ejecución, los tiempos de espera de la conexión del cliente no le permiten enviar una respuesta. Entonces, lo que puede hacer es enviar un 202 aceptado después de poner los comandos en la cola y agregar un enlace de sondeo, para que el cliente pueda sondear los cambios. Sus tareas tienen múltiples subtareas, por lo que hay progreso, no solo cambios de estado pendientes y completos.
- Si desea seguir con el sondeo, debe crear un nuevo recurso REST, que contenga el estado real y el progreso de la tarea de ejecución larga. Esto significa que debe almacenar esta información en una base de datos, para que el servicio REST pueda responder a solicitudes como
GET /tasks/23461/status
. Esto significa que su trabajador debe actualizar la base de datos cuando se completa una subtarea o toda la tarea. - Si su servicio REST se ejecuta como daemon, puede notificarlo por progreso, por lo que el almacenamiento del estado de la tarea en la base de datos no será responsabilidad del trabajador. Este tipo de servicio REST también puede almacenar la información en la memoria.
- Si decide utilizar websockets para notificar al cliente, puede crear un servicio de notificación. Por REST tiene que responder con una identificación de tarea. Después de que envíe de vuelta esta identificación de tarea en la conexión websocket, el servicio de notificación sabrá qué conexión de websocket se suscribió a los eventos de una determinada tarea. Después de eso, no necesitará el servicio REST, puede enviar el progreso a través de la conexión websocket siempre que el cliente no cierre la conexión.
- Puede combinar estas soluciones de la siguiente manera. Dejó que su servicio REST cree un recurso de tarea, por lo que podrá acceder al progreso utilizando un enlace de sondeo. Después de eso, devuelve un identificador con 202 que se envía a través de la conexión websockets. Entonces puede usar un servicio de notificación para notificar al cliente. Por progreso, su trabajador notificará al servicio REST, que creará un enlace como
GET /tasks/23461/status
y enviará ese enlace al cliente a través del servicio de notificación. Después de eso, el cliente puede usar el enlace para actualizar su estado.
Creo que la última es la mejor solución si su servicio REST se ejecuta como daemon. Es porque puede trasladar la responsabilidad de notificación a un servicio de notificación dedicado, que puede usar websockets, encuestas, SSE, lo que quiera. Puede colapsar sin matar el servicio REST, por lo que el servicio REST se mantendrá estable y rápido. Si envía un enlace de actualización manual también con el 202, entonces el cliente puede hacer la actualización manual (suponiendo que un cliente controlado por humanos), por lo que tendrá algo así como la degradación elegante si el servicio de notificación no está disponible. No tiene que mantener el servicio de notificación porque no sabrá nada sobre las tareas, simplemente enviará datos a los clientes. Su trabajador no tendrá que saber nada sobre cómo enviar notificaciones y cómo crear hipervínculos. También será más fácil mantener el código del cliente, ya que será casi un cliente REST puro. La única característica adicional será la suscripción a los enlaces de notificación, que no cambia con frecuencia.
Estamos implementando una API REST, que iniciará múltiples tareas backend de larga ejecución. He estado leyendo el RESTful Web Services Cookbook y la recomendación es devolver HTTP 202 / Accepted con un encabezado Content-Location que apunte a la tarea que se está procesando. (p. ej., http://www.example.org/orders/tasks/1234 ) y solicite al cliente que realice una encuesta sobre esta URI para obtener una actualización de la tarea de ejecución prolongada.
La idea es hacer que la API REST publique inmediatamente un mensaje en una cola, con una función de trabajador de fondo que recoge el mensaje de la cola y girando varias tareas back-end, también usando colas. El problema que veo con este enfoque es cómo asignar un ID único a la tarea y, posteriormente, dejar que el cliente solicite un estado de la tarea emitiendo un GET al URI de ubicación de contenido.
Si la API REST se publica inmediatamente en una cola, podría generar un GUID y adjuntar eso como un atributo en el mensaje que se agrega a la cola, pero recuperar el estado de la solicitud resulta incómodo.
Otra opción sería que la API REST agregue inmediatamente una entrada a la base de datos (digamos un pedido, con una nueva ID de pedido), con un estado inicial y luego coloque un mensaje en la cola para iniciar las tareas secundarias, que posteriormente actualizaría ese registro de la base de datos. La API devolvería esta nueva ID de orden en el URI del encabezado Content-Location, para que el cliente la use al verificar el estado de la tarea.
De alguna manera, agregar primero la entrada a la base de datos y luego agregar el mensaje a la cola parece ser al revés, pero solo agregar la solicitud a la cola dificulta el seguimiento del progreso.
¿Cuál sería el enfoque recomendado?
Muchas gracias por sus ideas.