API REST de larga ejecución con colas


Estamos implementando una API REST, que iniciará múltiples tareas de backend de larga duración. He estado leyendo el Libro de cocina RESTful Web Services y la recomendación es devolver HTTP 202 / Accepted con un encabezado Content-Location apuntando a la tarea que se está procesando. (por ejemplo, http://www.example.org/orders/tasks/1234 ), y hacer que el cliente sondee este URI para obtener una actualización sobre la tarea de larga ejecución.

La idea es que la API REST publique inmediatamente un mensaje en una cola, con un rol de trabajador en segundo plano recogiendo el mensaje de la cola y girando varias tareas de backend, también usando colas. El problema que veo con este enfoque es cómo asignar un ID único a la tarea y, posteriormente, permitir que el cliente solicite un estado de la tarea emitiendo un URI GET to the Content-Location.

Si la API REST inmediatamente publica en una cola, entonces podría generar un GUID y adjuntarlo como un atributo en el mensaje que se agrega a la cola, pero obteniendo el estado de la la petición se vuelve incómoda.

Otra opción sería hacer que la API REST agregue inmediatamente una entrada a la base de datos (digamos un pedido, con un nuevo id de pedido), con un estado inicial y luego ponga un mensaje en la cola para iniciar las tareas de fondo, que luego actualizaría ese registro de la base de datos. La API devolvería este nuevo ID de orden en el URI del encabezado Content-Location, para que el cliente lo utilizara al comprobar el estado de la tarea.

De alguna manera agregar la entrada de la base de datos primero, luego agregar el mensaje a la cola parece 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.

Author: user2079172, 2015-10-08

1 answers

Asumo que su sistema se ve como el siguiente. Tiene un servicio REST, que recibe solicitudes del cliente. Convierte las solicitudes en comandos que la lógica de negocio puede entender. Pones estos comandos en una cola. Tiene uno 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 que por sus tareas de larga ejecución los tiempos de espera de conexión del cliente, así que no puedes 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 varias subtareas, por lo que hay progreso, no solo cambios de estado pendientes y completos.

  1. Si desea seguir con el sondeo, debe crear un nuevo recurso REST, que contenga el estado real y el progreso de la tarea de larga ejecución. Esto significa que usted tiene que almacenar esta información en una base de datos, por lo que el servicio REST será capaz de responder a solicitudes como GET /tasks/23461/status. Esto significa que su trabajador tiene que actualizar la base de datos cuando se completa una subtarea o toda la tarea.
  2. Si su servicio REST se está ejecutando como un demonio, entonces puede notificarlo por progreso, por lo que almacenar el 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.
  3. Si decide utilizar websockets para notificar a la cliente, a continuación, puede crear un servicio de notificación. Por REST tienes que responder con un id de tarea. Después de eso, devuelve este id de tarea en la conexión websocket, para que el servicio de notificaciones sepa qué conexión websocket se suscribió a los eventos de una tarea determinada. Después de eso no necesitará el servicio REST, puede enviar el progreso a través de la conexión websocket siempre y cuando el cliente no cierre la conexión.
  4. Puede combinar estas soluciones de la siguiente manera. Deja que su servicio REST para crear un recurso de tarea, por lo que podrá acceder al progreso mediante un enlace de sondeo. Después de eso se envía de vuelta un identificador con 202 que se envía de vuelta a través de la conexión websockets. Por lo tanto, 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 que el cliente puede utilizar el enlace para actualizar su estatus.

Creo que la última es la mejor solución si su servicio REST se ejecuta como un demonio. Se debe a que puede mover la responsabilidad de notificación a un servicio de notificación dedicado, que puede usar websockets, polling, SSE, lo que desee. Puede colapsar sin matar el servicio REST, por lo que el servicio REST se mantendrá estable y rápido. Si devuelve un enlace de actualización manual también con el 202, entonces el cliente puede hacer una actualización manual (suponiendo que sea un cliente controlado por humanos), por lo que tendrá algo así como degradación agraciada si el servicio de notificación no está disponible. No tiene que mantener el servicio de notificaciones porque no sabrá nada sobre las tareas, solo 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 para la notificación enlaces, que no cambia con frecuencia.

 41
Author: inf3rno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-12 23:19:17