|
7 min de lectura
|

Patrón unificado de operaciones FHIR asíncronas

Resumir este artículo con:
ChatGPTPerplexityClaudeGrok

Algunas operaciones son computacionalmente intensivas y pueden tardar minutos o incluso horas (exportación masiva, reindexación de parámetros de búsqueda, revalidación completa de recursos). Ejecutarlas de forma asíncrona evita bloquear al cliente y permite que el servidor gestione la carga. En un flujo asíncrono, el cliente inicia el trabajo, el servidor lo ejecuta en segundo plano y el cliente sondea el estado o recibe una notificación cuando este finaliza.

FHIR ya ofrece soporte asíncrono a través de Bulk Data Access y el patrón de solicitud de interacción asíncrona de R5. Ambos comparten el mismo ciclo de vida:

  • Solicitud de inicio → 202 Accepted con Content-Location.

  • Solicitud de estado (mientras se ejecuta) → 202 Accepted con Retry-After y, opcionalmente, X-Progress.

  • Cancelación opcional → DELETE a la URL de estado devuelve 202 Accepted.

  • Estado terminal → 200 OK (payload en línea) o 303 See Other (redirección al payload).

Los modos en línea (Bundle, manifiesto Bulk) siempre devuelven 200 OK al completarse; el éxito o el fallo se indica mediante el payload (por ejemplo, un Bundle de resultado frente a un OperationOutcome, o enlaces de error dentro de un manifiesto). El modo Redirect expone los códigos de estado sincrónicos originales en la solicitud redirigida (por ejemplo, 200/201 en caso de éxito, 4XX/5XX en caso de fallo).

Los patrones se diferencian principalmente por el formato del payload final:

  • Bulk Data Access devuelve un manifiesto JSON personalizado.
  • La solicitud de interacción asíncrona devuelve un Bundle FHIR.
  • El modo Redirect devuelve lo que habría devuelto la interacción síncrona (Parameters, Bundle, Binary, etc.).

Esto plantea problemas cuando el payload no puede expresarse como un Bundle (por ejemplo, salidas en streaming o contenido binario).

El trabajo en R6 tiene como objetivo estandarizar las operaciones asíncronas en todas las interacciones. Cada interacción permite ahora 202 Accepted, y el borrador de especificación de Josh propone un patrón de redirección adicional: la respuesta de estado terminal es 303 See Other con un Location que apunta al resultado; ese endpoint devuelve el payload real y su estado.

Lo ideal sería unificar estos patrones en uno único parametrizado. Se utiliza Prefer: respond-async junto con un token Prefer personalizado para solicitar el modo. Por compatibilidad con versiones anteriores, el valor predeterminado es bundle; si _outputFormat está presente, la solicitud se trata como Bulk y se devuelve un manifiesto (los servidores PUEDEN rechazar un async-mode en conflicto con 400 Bad Request).

GET /fhir/[$operation] HTTP/1.1
Prefer: respond-async, async-mode=[redirect|bundle]   # async-mode is a proposed extension token

Los servidores DEBERÍAN confirmar las preferencias aceptadas mediante Preference-Applied.

Los clientes deben asumir que los tokens Prefer desconocidos serán ignorados y estar preparados para recurrir al modo bundle predeterminado.

Cuando la operación finaliza:

  • async-mode=bundle: el servidor DEBERÍA responder con 200 OK y un cuerpo Bundle; los fallos utilizan un payload OperationOutcome.

  • Parámetro _outputFormat presente: el servidor DEBERÍA responder con 200 OK y un cuerpo Bulk Manifest; los fallos se indican mediante enlaces de error del manifiesto y/o una entrada OperationOutcome.

  • async-mode=redirect: el servidor DEBERÍA responder con 303 See Other y una URL Location que apunte al resultado de la operación; la solicitud redirigida devuelve los mismos códigos de estado que la interacción síncrona.

Los clientes pueden deducir la finalización y el modo a partir del código de estado (200 o 303); el éxito o el fallo depende del payload final o del estado de la respuesta redirigida.

Extensiones

A continuación se presenta una lista de extensiones adicionales que pueden incorporarse para mejorar el soporte de operaciones asíncronas:

Extensión de long polling

Los servidores pueden utilizar long polling para las solicitudes de estado y minimizar así la latencia. El servidor mantiene la conexión abierta hasta que la operación finaliza o se agota el tiempo de espera. Cuando se agota el tiempo, el cliente reintenta y el servidor controla la frecuencia de las solicitudes de estado entrantes. El long polling reduce el tráfico de sondeo innecesario y, al mismo tiempo, garantiza una notificación rápida cuando el estado cambia (finalización o cancelación).

Extensión de callback

Propósito: permitir que el servidor notifique al cliente cuando un trabajo finaliza, de modo que el cliente pueda pausar o detener el sondeo.

Motivación: los callbacks mantienen una baja latencia de respuesta sin necesidad de un sondeo agresivo. Los clientes pueden reducir la frecuencia a sondeos lentos y económicos (o ninguno) y, aun así, recibir una notificación casi en tiempo real cuando el trabajo finaliza.

Flujo:

  • El cliente incluye callback-url junto con Prefer: respond-async (y async-mode opcional).

  • Cuando el trabajo finaliza o se cancela, el servidor envía un único POST a esa URL.

  • Si el callback falla o no llega, el cliente recurre al sondeo.

Ejemplo de inicio con callback:

POST /fhir/$operation HTTP/1.1
Prefer: respond-async, async-mode=redirect, callback-url=https://example.com/callback
Accept: application/fhir+json
Content-Type: application/fhir+json

{ ...normal operation body... }

Payload: un recurso FHIR Parameters que contiene:

  • status (completed | failed | cancelled)

  • resultUrl (URL desde la que el cliente puede obtener el payload final)

  • Parámetro OperationOutcome opcional cuando el trabajo ha fallado

Entrega: mejor esfuerzo, sin reintentos; los callbacks son una señal, no el canal de entrega principal (el sondeo lo es). Los callbacks DEBERÍAN ser idempotentes para que los duplicados sean inocuos.

Seguridad: los servidores DEBERÍAN autenticar los callbacks (por ejemplo, mediante token bearer OAuth2, mTLS o HMAC).

Gestión por parte del cliente: responder con 2XX en caso de éxito; una respuesta distinta de 2XX simplemente indica que el cliente recurrirá al sondeo.

Ejemplo de solicitud de callback:

POST https://example.com/callback HTTP/1.1
Content-Type: application/fhir+json
Authorization: Bearer eyJhbGciOi...

{
  "resourceType": "Parameters",
  "parameter": [
    { "name": "status", "valueCode": "completed" },
    { "name": "resultUrl", "valueUrl": "https://fhir.example.com/whatever/path/1ab7162f-result" }
  ]
}

Flujos visuales de ejemplo

A continuación se presentan algunos flujos visuales de ejemplo para los distintos modos.

Modo Bulk Manifest

Modo Bundle

Modo Redirect

Flujo de cancelación

Modo Callback

¿Tiene preguntas? Consulte a nuestro CTO

Si tiene más preguntas sobre este patrón, no dude en ponerse en contacto directamente con nuestro CTO, Nikolai Ryzhikov. Siempre estamos encantados de hablar sobre FHIR e implementaciones en el mundo real.

Véase también: Suscripciones basadas en temas: los 5 casos de uso principales y Construcción de microservicios sanitarios.

Compartir este artículo
Comments
Comments
Sign in
Loading comments...
Subscribe to our blog

Get the latest articles on FHIR, interoperability, and healthcare IT.