Código de estado HTTP para "Procesamiento continuo"

38

Estoy creando una API RESTful que admite la puesta en cola de tareas de larga ejecución para el manejo eventual.

El flujo de trabajo típico para esta API sería:

  1. El usuario rellena el formulario
  2. El cliente publica datos en la API
  3. API devuelve 202
  4. El cliente redirige al usuario a una URL única para esa solicitud ( /results/{request_id} )
  5. ~ eventualmente ~
  6. El cliente visita nuevamente la URL y ve los resultados en esa página.

Mi problema está en el paso 6. Cada vez que un usuario visita la página, presento una solicitud a mi API ( GET /api/results/{request_id} ). Lo ideal sería que la tarea se hubiera completado a estas alturas y obtendría un OK de 200 con los resultados de su tarea.

Pero los usuarios son agresivos, y espero muchas actualizaciones excesivas cuando el resultado aún no haya terminado de procesarse.

¿Cuál es mi mejor opción para que un código de estado indique que:

  • esta solicitud existe,
  • aún no está hecho,
  • pero tampoco ha fallado.

No espero que un solo código comunique todo eso, pero me gustaría algo que me permita pasar metadatos en lugar de que el cliente espere contenido.

Podría tener sentido devolver un 202, ya que aquí no tendría otro significado: es una solicitud GET , por lo que posiblemente no se "acepte" nada. ¿Sería esa una opción razonable?

La alternativa obvia a todo esto, que funciona, pero elimina un propósito de los códigos de estado, sería incluir siempre los metadatos:

200 OK

{
    status: "complete",
    data: {
        foo: "123"
    }
}

... o ...

200 OK

{
    status: "pending"
}

Luego, del lado del cliente, yo (suspira) switch en response.data.status para determinar si la solicitud se completó.

¿Es esto lo que debería estar haciendo? ¿O hay una alternativa mejor? Esto me parece muy web 1.0

    
pregunta Matthew Haugen 19.04.2016 - 19:46

4 respuestas

40

HTTP 202 aceptado (HTTP / 1.1)

Está buscando el estado de HTTP 202 Accepted . Consulte RFC 2616 :

  

La solicitud se ha aceptado para su procesamiento, pero el procesamiento no se ha completado.

Procesamiento HTTP 102 (WebDAV)

RFC 2518 sugiere usar HTTP 102 Processing :

  

El código de estado 102 (Procesamiento) es una respuesta provisional utilizada para      informar al cliente que el servidor ha aceptado la solicitud completa,      pero aún no lo ha completado.

pero tiene una advertencia:

  

El servidor DEBE enviar una respuesta final después de que se haya completado la solicitud.

No estoy seguro de cómo interpretar la última oración. ¿Debería el servidor evitar enviar algo durante el procesamiento y responder solo después de la finalización? ¿O solo obliga a finalizar la respuesta solo cuando finaliza el procesamiento? Esto podría ser útil si desea informar el progreso. Envíe HTTP 102 y vacíe el byte por byte (o línea por línea).

Por ejemplo, para un proceso largo pero lineal, puedes enviar cien puntos, limpiando después de cada personaje. Si el lado del cliente (como una aplicación de JavaScript) sabe que debe esperar exactamente 100 caracteres, puede coincidir con una barra de progreso para mostrar al usuario.

Otro ejemplo se refiere a un proceso que consta de varios pasos no lineales. Después de cada paso, puede vaciar un mensaje de registro que finalmente se mostraría al usuario, para que el usuario final pueda saber cómo va el proceso.

Problemas con el lavado progresivo

Tenga en cuenta que si bien esta técnica tiene sus ventajas, no la recomendaría . Una de las razones es que obliga a que la conexión permanezca abierta, lo que podría perjudicar en términos de disponibilidad del servicio y no se escala bien.

Un mejor enfoque es responder con HTTP 202 Accepted y dejar que el usuario se comunique con usted más tarde para determinar si el procesamiento terminó (por ejemplo, llamando repetidamente a un URI determinado, como /process/result , que respondería con HTTP 404 No encontrado o HTTP 409 Conflict hasta que el proceso finalice y el resultado esté listo), o notifique al usuario cuando se realice el procesamiento si puede devolver la llamada al cliente, por ejemplo, a través de un servicio de cola de mensajes ( example ) o WebSockets.

Ejemplo práctico

Imagina un servicio web que convierte videos. El punto de entrada es:

POST /video/convert

que toma un archivo de video de la solicitud HTTP y hace algo de magia con él. Imaginemos que la magia requiere mucha CPU, por lo que no se puede realizar en tiempo real durante la transferencia de la solicitud. Esto significa que una vez que se transfiere el archivo, el servidor responderá con un HTTP 202 Accepted con algo de contenido JSON, lo que significa "Sí, recibí tu video y estoy trabajando en ello; estará listo en algún lugar en el futuro y estará disponible a través de la ID 123 ".

El cliente tiene la posibilidad de suscribirse a una cola de mensajes para recibir una notificación cuando finalice el procesamiento. Una vez finalizado, el cliente puede descargar el video procesado yendo a:

GET /video/download/123

que lleva a un HTTP 200 .

¿Qué sucede si el cliente consulta este URI antes de recibir la notificación? Bueno, el servidor responderá con HTTP 404 ya que, de hecho, el video todavía no existe. Puede estar actualmente preparado. Puede que nunca haya sido solicitado. Puede existir algún tiempo en el pasado y ser eliminado más tarde. Lo único que importa es que el video resultante no está disponible.

Ahora, ¿qué pasa si al cliente no solo le interesa el video final, sino también el progreso (que sería aún más importante si no hay un servicio de cola de mensajes o algún mecanismo similar)?

En este caso, puede utilizar otro punto final:

GET /video/status/123

lo que daría como resultado una respuesta similar a esta:

HTTP 200
{
    "id": 123,
    "status": "queued",
    "priority": 2,
    "progress-percent": 0,
    "submitted-utc-time": "2016-04-19T13:59:22"
}

Hacer la solicitud una y otra vez mostrará el progreso hasta que sea:

HTTP 200
{
    "id": 123,
    "status": "done",
    "progress-percent": 100,
    "submitted-utc-time": "2016-04-19T13:59:22"
}

Es crucial hacer una diferencia entre esos tres tipos de solicitudes:

  • POST /video/convert pone en cola una tarea. Se debe llamar solo una vez: volver a llamar sería una tarea adicional.
  • GET /video/download/123 se refiere al resultado de la operación: el recurso es el video. El procesamiento, que es lo que sucedió bajo el capó para preparar el resultado real antes de la solicitud e independientemente de la solicitud, es irrelevante aquí. Se puede llamar una o varias veces.
  • GET /video/status/123 se refiere al procesamiento per se . No hace cola nada. No le importa el video resultante. El recurso es el procesamiento en sí mismo. Se puede llamar una o varias veces.
respondido por el Arseni Mourzenko 19.04.2016 - 20:07
3
  

La alternativa obvia a todo esto, que funciona, pero es derrota.   Un propósito de los códigos de estado - sería incluir siempre la   metadatos:

Esta es la manera correcta de ir. El estado en que se encuentran los recursos con respecto al registro específico del dominio (también conocida como lógica de negocios) es una cuestión del tipo de contenido de la representación del recurso.

Aquí se combinan dos conceptos diferentes que son realmente diferentes. Uno es el estado de la transferencia de estado entre el cliente y el servidor de un recurso, y el otro es el estado del recurso en cualquier contexto en el que el dominio empresarial entienda los diferentes estados de ese recurso. Lo último no tiene nada que ver con los códigos de estado HTTP.

Recuerde que los códigos de estado HTTP corresponden a la transferencia de estado entre el cliente y el servidor del recurso que se está tratando, independientemente de cualquier detalle de ese recurso. Cuando GET un recurso, su cliente le está pidiendo al servidor una representación de un recurso en el estado actual en que se encuentra. Esa podría ser una imagen de un ave, podría ser un documento de Word, podría ser la temperatura exterior actual. . El protocolo HTTP no le importa. El código de estado HTTP corresponde al resultado de esa solicitud. ¿El POST del cliente al servidor transfirió un recurso al servidor, donde el servidor le dio una URL que el cliente puede ver? ¿Sí? Entonces eso es una respuesta 201 Created .

El recurso podría ser una reserva de una aerolínea que se encuentra actualmente en el estado 'para ser revisado'. O podría ser una orden de compra del producto que se encuentre en el estado "aprobado". Esos estados son específicos del dominio y no de lo que trata el protocolo HTTP. El protocolo HTTP se ocupa de la transferencia de recursos entre el cliente y el servidor.

El punto de REST y HTTP es que los protocolos no se ocupan de los detalles de los recursos. Esto es a propósito, no se ocupa de los problemas específicos del dominio, por lo que se puede utilizar sin tener que saber nada sobre los problemas específicos del dominio. No reinterpreta lo que significan los códigos de estado HTTP en cada contexto diferente (un sistema de reserva de una aerolínea, un sistema de procesamiento de imágenes, un sistema de seguridad de video, etc.).

Las cosas específicas del dominio son para que el cliente y el servidor se resuelvan entre sí basándose en el Content Type del recurso. El protocolo HTTP es agnóstico a esto.

En cuanto a cómo el cliente se da cuenta de que el recurso de Solicitud ha cambiado de estado, el sondeo es su mejor apuesta ya que mantiene el control en el cliente y no asume una conexión ininterrumpida. Particularmente si va a ser potencialmente horas hasta que cambie el estado. Incluso si dijiste al diablo con REST, solo mantendrías la conexión abierta, mantenerla abierta durante horas y suponiendo que nada saldría mal sería una mala idea. ¿Qué pasa si el usuario cierra el cliente o la red se apaga? Si la granularidad es en horas, el cliente solo puede solicitar el estado cada pocos minutos hasta que la Solicitud cambie de "pendiente" a "listo".

Espero que ayude a aclarar las cosas

    
respondido por el Cormac Mulhall 21.04.2016 - 17:48
2

El código de estado HTTP del recurso aún no está disponible sugiere devolver una respuesta de conflicto 409, en lugar de una respuesta 404, en el caso de que un recurso no exista porque está en medio de ser generado.

De la w3 spec :

  

10.4.10 409 Conflicto

     

La solicitud no se pudo completar debido a un conflicto con el actual   Estado del recurso. Este código solo está permitido en situaciones donde   se espera que el usuario pueda resolver el conflicto y   vuelva a enviar la solicitud. El cuerpo de respuesta DEBE incluir suficiente

     

información para que el usuario reconozca la fuente del conflicto.   Idealmente, la entidad de respuesta incluiría suficiente información para la   usuario o agente de usuario para solucionar el problema; sin embargo, eso podría no ser   posible y no es obligatorio.

     

Es más probable que ocurran conflictos en respuesta a una solicitud PUT. por   ejemplo, si se estaban utilizando las versiones y la entidad se PUT   incluye cambios en un recurso que está en conflicto con los realizados por un   solicitud anterior (de terceros), el servidor podría usar la respuesta 409   para indicar que no puede completar la solicitud. En este caso, la   La entidad de respuesta probablemente contendría una lista de las diferencias entre   las dos versiones en un formato definido por la respuesta tipo de contenido.

Esto es un poco incómodo, ya que el código 409 "solo se permite en situaciones en las que se espera que el usuario pueda resolver el conflicto y volver a enviar la solicitud". Sugiero que el cuerpo de la respuesta incluya un mensaje (posiblemente en algún formato de respuesta que coincida con el resto de su API) como, "Este recurso se está generando actualmente. Se inició en [HORA] y se estima que se completará en [HORA]. Por favor inténtalo de nuevo más tarde. "

Tenga en cuenta que solo sugeriría el enfoque 409 si es muy probable que el usuario que solicita el recurso sea también el usuario que inició la generación de ese recurso. Los usuarios que no participan en la generación del recurso encontrarán un error 404 menos confuso.

    
respondido por el Brian 20.04.2016 - 18:55
2

Me parecieron razonables las sugerencias de este blog: REST y trabajos de larga duración .

Para resumir:

  1. El servidor devuelve el código "202 Aceptado" con el encabezado "Ubicación" establecido en un URI para que el cliente verifique el estado, por ejemplo. "/ queue / 12345".
  2. Hasta que finalice el procesamiento, el servidor responde a las consultas de estado con "200 OK" y algunos datos de respuesta que muestran el estado del trabajo.
  3. Una vez que finaliza el procesamiento, el servidor responde a las consultas de estado con "303 Ver otros" y "Ubicación" que contiene un URI al resultado final.
respondido por el Xiangming Hu 16.11.2018 - 18:58

Lea otras preguntas en las etiquetas