Tema representativo de entrevista

Entrevista de backend: ¿cómo diseñar una API para operaciones de larga duración?

BackendDifícil
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

La exportación de un reporte multiinquilino toma de 5 minutos a 3 horas. Los clientes pueden reintentar tras un tiempo de espera y necesitan inspeccionar el progreso, cancelar el trabajo y descargar el resultado. Diseñe la API asíncrona cubriendo la semántica HTTP, el recurso de operación, la idempotencia, las transiciones de estado, las notificaciones, la autorización, la recuperación ante fallos y la verificación.

Enunciado y alcance

Una plataforma de analítica B2B necesita una API para la exportación de reportes. Una exportación toma de 5 minutos a 3 horas y puede generar un archivo de hasta 20 GiB. El servicio puede recibir 10,000 envíos alrededor de las 09:00 cada día. Quienes realizan las llamadas incluyen navegadores y servicios operados por otras empresas. El gateway de la API cierra una solicitud sincrónica después de 30 segundos, por lo que los clientes pueden reintentar cuando no reciben una respuesta.

Los usuarios deben ver si el trabajo está en cola, ejecutándose, exitoso o fallido. También necesitan solicitar la cancelación mientras sea posible y descargar un resultado exitoso. Las duraciones, el tamaño del archivo, el pico y el tiempo de espera son suposiciones del caso de entrevista, no umbrales de la industria. La partición de colas queda fuera del foco central de esta pregunta. La tarea principal es definir un contrato HTTP asíncrono que siga siendo comprensible frente a reintentos, caídas de procesos y condiciones de carrera en el estado.

La RFC 9110 indica que 202 Accepted significa que una solicitud ha sido aceptada para su procesamiento, pero el procesamiento está incompleto y podría no ocurrir nunca. La respuesta debe describir el estado actual y apuntar a un monitor de estado. Una guía actual de entrevistas de API REST para niveles senior también pide a los candidatos diseñar operaciones de larga duración, incluyendo estado, fallos, cancelación e idempotencia. La pregunta se adapta a ingenieros de backend, ingenieros de plataformas de API y desarrolladores senior full-stack que diseñan contratos de servicios, por lo que su categoría principal es backend.

Qué evalúa el entrevistador

Primero, ¿comprende el candidato el límite de 202? No significa "el trabajo en segundo plano tendrá éxito", y el trabajo no terminado no es un resultado final 200 OK. Una respuesta sólida rechaza de forma sincrónica las solicitudes inválidas detectables de inmediato, luego devuelve un recurso de operación estable tras una aceptación duradera y expone el resultado de la ejecución como un estado posterior.

Segundo, ¿puede el candidato modelar el trabajo de larga duración como un recurso en lugar de devolver únicamente el ID de un mensaje en cola? Una operación necesita un inquilino propietario, una huella digital de la solicitud, estado, progreso, resultado o error, versión, marca de tiempo de creación y expiración. Su máquina de estados debe definir las transiciones permitidas, los estados terminales y las carreras de cancelación.

Tercero, ¿existe una brecha en la que el servidor ha devuelto 202 pero el trabajo nunca se encola? El registro de la operación y el trabajo a publicar deben persistirse en una sola transacción, y luego un publicador outbox puede encolarlo. Los consumidores y las etapas de ejecución aún necesitan idempotencia, ya que la entrega al menos una vez (at-least-once), las caídas de workers y la toma de posesión del lease pueden duplicar el trabajo.

Cuarto, ¿puede el contrato del cliente sobrevivir al tráfico real? Location le indica al cliente dónde inspeccionar el estado. Retry-After, el retroceso exponencial (backoff), la fluctuación aleatoria (jitter) y las solicitudes condicionales controlan el sondeo. Los webhooks firmados pueden notificar a los llamadores servidor a servidor, y SSE puede actualizar un navegador, pero ninguno reemplaza a un recurso de operación consultable para fines de recuperación.

Finalmente, el entrevistador debe escuchar una propuesta de seguridad y verificación. Un ID imposible de adivinar no constituye autorización a nivel de objeto, y la URL de un resultado no debe eludir los límites entre inquilinos. Una respuesta sólida prueba respuestas de aceptación perdidas, envíos duplicados, fallos de publicación, caídas de workers, carreras entre cancelación y finalización, ráfagas de sondeo y limpieza por expiración.

Preguntas para clarificar primero

  • ¿Qué se debe validar de forma sincrónica? La identidad, los permisos del inquilino, la estructura de la solicitud, la existencia de los datos de entrada y las violaciones evidentes de cuota deben comprobarse antes de la aceptación. Si la completitud de los datos solo puede saberse tras un escaneo de varias horas, eso constituye un fallo de ejecución asíncrona, no una promesa hecha al momento de la aceptación.
  • ¿Una solicitud duplicada significa un reintento o una segunda operación independiente? Cuando los llamadores proporcionan un Idempotency-Key, el mismo inquilino, endpoint, clave y huella digital de la solicitud deben reproducir una sola operación. Un llamador que intencionalmente necesite dos exportaciones idénticas debe usar dos claves.
  • ¿Es medible el progreso? Si se conoce el número total de particiones, reporte las unidades completadas y las totales. Si no es estimable, reporte la fase y el último latido (heartbeat) en lugar de inventar un porcentaje que se estanque en el 99%.
  • ¿Qué tipo de recurso es el resultado? Un resultado pequeño puede incrustarse en la respuesta de la operación. Un archivo grande debe ser un recurso protegido independiente. Este caso utiliza credenciales de descarga de corta duración y períodos de retención separados para los metadatos de la operación, los objetos de resultado y las credenciales de descarga.
  • ¿Qué promete la cancelación? ¿Detiene solo el trabajo futuro o debe revertir los efectos secundarios ya aplicados? Si los pasos son irreversibles, el contrato debe definir una cancelación de mejor esfuerzo, compensación, salida parcial y los posibles estados finales.
  • ¿Qué canales de notificación pueden recibir los llamadores? Los navegadores normalmente no pueden alojar endpoints de callback, por lo que el sondeo o SSE son adecuados. Los llamadores servidor a servidor pueden usar webhooks. Las restricciones de red y los objetivos de latencia cambian el canal de notificación, pero el recurso de operación sigue siendo la fuente de la verdad.
  • ¿Pueden entrar en conflicto las operaciones paralelas? ¿Se puede exportar la misma configuración de reporte de forma concurrente? ¿Qué sucede cuando esa configuración se actualiza o elimina durante la ejecución? La respuesta determina si se debe serializar, tomar una instantánea de las entradas, rechazar conflictos o permitir que termine la versión anterior.
  • ¿Cuánto tiempo se retiene el estado? El caso retiene las operaciones terminales durante 7 días, los objetos de resultado durante 24 horas y cada credencial de descarga durante 15 minutos. Estas son decisiones del contrato del producto que deben ajustarse según las necesidades de auditoría, el costo y la capacidad de regenerar resultados.

Estructura de respuesta de 30 segundos

"Separaría la ejecución de la solicitud HTTP, pero no devolvería solo un ID de trabajo. El endpoint de envío valida la autorización y los errores detectables de inmediato, y luego escribe una operación y un registro outbox en una sola transacción. Una vez confirmada, devuelve 202, Location y un intervalo de sondeo sugerido. Un recurso de operación autorizado expone un estado estable, progreso real, errores estructurados y el enlace al resultado. La misma clave de idempotencia y solicitud reproducen la misma operación. Los workers procesan por ID de operación de forma idempotente, mientras que las condiciones de versión protegen las transiciones de estado. El sondeo utiliza Retry-After, retroceso exponencial y fluctuación; los llamadores de servidor pueden añadir webhooks firmados; la cancelación pasa a cancel_requested y resuelve su carrera frente a la finalización. Luego inyectaría respuestas perdidas, mensajes duplicados, caídas de workers, carreras de cancelación y expiración para demostrar que no hay trabajos fantasma, resultados visibles duplicados ni descargas no autorizadas".

Análisis detallado paso a paso

Primero, defina dos recursos. Una solicitud de exportación expresa el resultado que el usuario desea crear, mientras que un recurso de operación representa el ciclo de vida de esta ejecución. El envío puede ser POST /v1/report-exports y el estado puede ser GET /v1/report-operations/{operation_id}. La respuesta de aceptación puede ser:

http
HTTP/1.1 202 Accepted
Location: /v1/report-operations/op_7f3a
Retry-After: 5
Content-Type: application/json

{
  "id": "op_7f3a",
  "status": "queued",
  "statusUrl": "/v1/report-operations/op_7f3a",
  "cancelUrl": "/v1/report-operations/op_7f3a"
}

202 solo promete que el procesamiento fue aceptado. Rechace una solicitud malformada, un llamador no autorizado o una entrada inexistente con el 4xx correspondiente y no cree una operación. Persista en el recurso de operación un fallo de negocio que requiera un cómputo costoso. Location y Retry-After forman parte del contrato de cliente de esta API; la RFC 9110 no exige que toda respuesta 202 use ambos encabezados.

Segundo, defina el registro de la operación y la máquina de estados. Un registro mínimo contiene id, tenant_id, idempotency_key, request_fingerprint, status, progreso, una referencia al resultado, un error estructurado, version, marcas de tiempo de creación y actualización, y expires_at. Un conjunto recomendado de transiciones es:

text
queued -> running -> succeeded
                 -> failed
queued  -> cancel_requested -> canceled
running -> cancel_requested -> canceled | succeeded | failed

La cancelación y la finalización pueden competir, por lo que cancel_requested no es terminal. Un worker confirma un resultado con una actualización condicional sobre version y un estado previo permitido; solo una transición gana. Si un efecto secundario ya es irreversible, la cancelación podría terminar convirtiéndose en succeeded o failed. No fabrique canceled solo para coincidir con la etiqueta del botón. Una representación de estado puede verse así:

json
{
  "id": "op_7f3a",
  "status": "running",
  "progress": {
    "completedUnits": 37,
    "totalUnits": 100
  },
  "result": null,
  "error": null,
  "lastUpdatedAt": "2026-07-18T23:18:11Z",
  "expiresAt": "2026-07-25T23:08:11Z"
}

Devuelva este progreso solo cuando las unidades de trabajo tengan un denominador real. Una ejecución fallida aún puede devolver 200 cuando la operación en sí se lee con éxito, representándose el fallo mediante un estado terminal y un error estructurado: la lectura del estado fue exitosa mientras que la ejecución representada falló. Un equipo que en su lugar asigne el fallo de ejecución a un 4xx desde el endpoint de estado debe usar esa convención de manera consistente en todos los SDK en lugar de mezclar ambos significados.

Tercero, asegure que la aceptación, los reintentos y la ejecución sean correctos. Aplique una restricción única en (tenant_id, route, idempotency_key) y almacene una huella digital de la solicitud canónica. La misma clave y huella digital devuelven la operación existente y el estado actual. La misma clave con una huella digital diferente devuelve un conflicto explícito, evitando la reutilización accidental de la clave para otro reporte. Retenga el registro de idempotencia al menos durante el tiempo en que los clientes puedan reintentar legítimamente y coordínelo con la retención de la operación.

Inserte la operación y el evento outbox en una sola transacción de base de datos, y luego devuelva 202. Un publicador independiente envía el evento outbox a la cola y puede enviarlo más de una vez. Los consumidores deduplican por ID de operación. Cada etapa de ejecución también necesita escrituras idempotentes o un fencing token para que la caída de un worker tras una escritura externa, seguida de una toma de posesión, no produzca dos resultados visibles. La respuesta de la API debe demostrar el límite entre la aceptación y la cola; no necesita reproducir el diseño completo de un planificador.

Cuarto, controle el tráfico de estado y notificaciones. Las respuestas de estado iniciales y posteriores proporcionan un Retry-After razonable. Los clientes utilizan un retroceso exponencial con un límite y fluctuación, mientras que el servidor soporta ETag y solicitudes condicionales para evitar reenviar un cuerpo sin cambios. Si las lecturas de estado superan la cuota, devuelva información de limitación de tasa (rate-limit) en lugar de permitir que 10,000 clientes sondeen cada segundo.

Un navegador que requiera progreso de baja latencia puede suscribirse a SSE y seguir consultando por ID de operación tras una desconexión. Un llamador de servidor puede registrar un webhook firmado; el emisor reintenta y el receptor deduplica. Ambos canales push pueden perderse, retrasarse o duplicarse, por lo que el recurso de operación sigue siendo la fuente de la verdad para la recuperación y la reconciliación. En caso de éxito, el cuerpo de la operación puede enlazar al resultado. Si la API en su lugar redirige a un recurso de resultado distinto, documente la semántica de 303 y verifique que los SDK no repitan el POST original en la ubicación del resultado.

Quinto, gestione la autorización, la cancelación y la retención. Cada lectura de estado, cancelación y obtención de resultado realiza una autorización a nivel de objeto sobre tenant_id, la identidad del llamador y los permisos de la operación. Los ID aleatorios dificultan la enumeración, pero no constituyen autorización. El servicio de descarga verifica nuevamente la propiedad del resultado y luego emite la credencial de 15 minutos seleccionada para este caso. La respuesta de la operación nunca almacena una URL pública de larga duración.

DELETE /v1/report-operations/{id} puede expresar una solicitud de cancelación. Si la cancelación es posible, devuelva la representación actual de cancel_requested para indicar que fue aceptada. Si es imposible o la operación ya es terminal, devuelva una respuesta estable que sea segura de reintentar. Los workers inspeccionan el marcador de cancelación en los límites de cada etapa, omiten los pasos futuros y eliminan los objetos temporales. Los efectos externos ya confirmados siguen una regla de compensación predefinida. Elimine una operación terminal tras 7 días. Un ID expirado conocido puede devolver 410 Gone, mientras que un ID desconocido o no autorizado puede devolver 404 según la política de divulgación.

Sexto, verifique los fallos en lugar de centrarse únicamente en el camino feliz. Cubra al menos estos casos: el servidor confirma pero pierde la respuesta 202, y un reintento solo puede recuperar la misma operación; el publicador outbox se cae antes o después del envío, y el trabajo finalmente existe con un único resultado visible; un worker pierde su confirmación (acknowledgement) tras escribir el resultado, y su sucesor no puede sobrescribir el estado terminal; la cancelación y la finalización llegan juntas, y solo aparece un estado terminal legal; el sondeo de estado sin cambios sigue el retroceso y las solicitudes condicionales; el estado, la cancelación y la descarga entre diferentes inquilinos fallan; los metadatos, resultados y claves de idempotencia expiran de acuerdo con el contrato.

La regla de decisión reutilizable es: 202 resuelve la espera de la conexión, el recurso de operación resuelve la observabilidad y la aceptación atómica junto con una máquina de estados idempotente resuelve la corrección.

Respuesta de muestra de alta calidad

"Primero separaría el éxito de la aceptación del éxito de la ejecución. La operación puede tomar 3 horas y no puede ocupar una conexión de gateway que dura 30 segundos. Por lo tanto, POST /v1/report-exports verifica la identidad, los permisos del inquilino, la estructura de la solicitud, la existencia de las entradas y las violaciones evidentes de cuota. Luego crea la operación y el registro outbox en una sola transacción y devuelve 202 solo tras el commit. La respuesta incluye Location para el recurso de operación y Retry-After para la primera lectura de estado. Un 202 no promete que el reporte tendrá éxito.

La operación almacena la propiedad del inquilino, la clave de idempotencia, la huella digital de la solicitud, el estado, el progreso verificable, el resultado o error, la versión y la expiración. El estado pasa de en cola a en ejecución y luego a exitoso o fallido. La cancelación primero entra en cancel_requested porque el worker podría estar confirmando un resultado al mismo tiempo. Bajo el mismo inquilino y endpoint, la misma clave de idempotencia y solicitud devuelven una sola operación; la misma clave con una solicitud diferente produce un conflicto. Por lo tanto, una respuesta 202 perdida no puede crear un segundo reporte cuando el cliente reintenta.

Asumo una entrega en cola de al menos una vez (at-least-once). El outbox puede publicar dos veces, los consumidores deduplican por ID de operación y las escrituras externas en cada etapa son idempotentes o utilizan fencing. Las actualizaciones de estado incluyen condiciones de versión para que un worker desactualizado no pueda sobrescribir el resultado después de que su lease haya sido revocado. Un fallo antes de la aceptación devuelve un 4xx de inmediato. Un fallo durante la ejecución se almacena como un estado terminal y un error estructurado, lo que permite a los clientes distinguir entre un fallo de red, un fallo en la lectura del estado y un fallo en la ejecución del reporte.

Los clientes sondean de acuerdo con Retry-After con retroceso exponencial y fluctuación, y el endpoint de estado soporta ETag. Un navegador puede usar SSE para ver el progreso en vivo y un servicio asociado puede usar un webhook firmado, pero ambos se recuperan a través del recurso de operación tras una desconexión o una notificación duplicada. El archivo resultante nunca tiene una URL pública. El endpoint de descarga autoriza nuevamente y emite una credencial de 15 minutos. En este caso, las operaciones terminales viven durante 7 días y los archivos durante 24 horas, y esas reglas de expiración forman parte del contrato público.

Finalmente, probaría una respuesta perdida tras el commit, entregas repetidas del outbox, la caída de un worker tras escribir un resultado, una carrera entre cancelación y finalización, 10,000 llamadores sondeando al mismo tiempo y accesos entre diferentes inquilinos. Aprobar significa más que completar el proceso una vez en segundo plano: estos fallos no deben generar trabajos fantasma, resultados visibles duplicados, transiciones ilegales ni descargas no autorizadas".

Errores comunes

  • Iniciar un hilo en memoria después de devolver 202 → un reinicio del proceso deja trabajo que nunca se podrá encontrar, y la aceptación no es atómica con respecto al lanzamiento → persista la operación y el outbox antes de confirmar la aceptación.
  • Tratar el 202 como éxito final → HTTP permite explícitamente que el procesamiento nunca ocurra o que falle → exponga el resultado final, los errores y un monitor de estado en el contrato posterior.
  • Devolver solo un ID de mensaje de cola → carece de propiedad de inquilino, estado estable, errores, resultados y retención → cree un recurso de operación autorizado independiente.
  • Sondear una vez por segundo indefinidamente → un pico de envíos se convierte en un pico sostenido de lecturas → proporcione Retry-After y utilice retroceso, fluctuación, ETag y cuotas.
  • Usar un ID de operación aleatorio como autorización → un registro filtrado, una entrada en el historial del navegador o un enlace interno seguirían otorgando acceso entre inquilinos → autorice cada lectura de estado, cancelación y obtención de resultado.
  • Mantener una clave de idempotencia únicamente en un bloqueo breve de Redis → la expiración del bloqueo, las caídas y la reproducción de resultados aún pueden crear operaciones duplicadas → utilice una restricción de unicidad duradera, una huella digital de la solicitud y una respuesta reproducible.
  • Marcar como cancelado tan pronto como el usuario hace clic → el worker podría haber confirmado ya un efecto irreversible → ingrese primero a cancel_requested y permita que las transiciones condicionales junto con la compensación determinen un estado terminal legal.
  • Inventar siempre un porcentaje → las fases impredecibles se estancan en el 99% y confunden a los clientes → reporte unidades completadas cuando sean medibles; de lo contrario, reporte la fase y la hora de actualización.
  • Eliminar la operación después de que un webhook tiene éxito → la notificación puede perderse, duplicarse o ser aceptada por un receptor temporalmente defectuoso → retenga la operación como una fuente de la verdad para la recuperación con límite de tiempo.

Preguntas de seguimiento

Pregunta de seguimiento 1: La transacción de la base de datos se confirmó, pero la respuesta 202 se perdió. ¿Qué sucede cuando el cliente vuelve a realizar el envío?

El cliente reutiliza el Idempotency-Key original. El servidor localiza la operación por inquilino, endpoint y clave, confirma que la huella digital de la solicitud coincide y reproduce la representación actual y Location sin insertar otra operación ni otro registro outbox. Si la clave coincide pero la solicitud difiere, devuelva un conflicto y exija una nueva clave. La prueba debe demostrar que existe una sola fila de operación y un único resultado visible, incluso si la entrega en cola se duplica.

Pregunta de seguimiento 2: La operación está al 90% de completarse. La cancelación y la confirmación del resultado llegan juntas. ¿Qué estado gana?

Defina transiciones legales por adelantado y utilice una actualización condicional por versión para seleccionar a un único ganador. Si la transacción del resultado confirma de running a succeeded primero, la cancelación posterior lee y devuelve el estado terminal succeeded. Si la cancelación alcanza cancel_requested primero, el worker comprueba si la finalización aún está permitida antes de confirmar. Una etapa irreversible puede hacer que cancel_requested termine legalmente en succeeded o failed; el contrato no puede prometer una reversión absoluta.

Pregunta de seguimiento 3: El progreso no es estimable, pero el equipo de producto insiste en mostrar un porcentaje. ¿Qué devuelve?

Explique que un porcentaje inventado genera falsas expectativas. Muestre las fases completadas, la fase actual, el último latido y un rango no vinculante derivado de ejecuciones históricas. Devuelva completedUnits / totalUnits solo cuando la carga de trabajo total sea estable. Si las fases individuales son medibles, muestre el progreso dentro de cada fase en lugar de promediar fases con costos diferentes.

Pregunta de seguimiento 4: Un socio se niega a realizar sondeos. ¿Debería la API exponer únicamente un webhook?

Un webhook puede reducir la latencia y las lecturas en la ruta normal, pero no puede ser el único mecanismo de recuperación. Los callbacks enfrentan fallos de DNS, certificados, firewalls, rotación de claves de firma, duplicados y desorden. Firme y reintente la entrega de webhooks, incluya el ID de la operación y la versión, y exija la deduplicación en el receptor. El socio puede conciliar a través del recurso de operación tras un evento perdido. Los navegadores sin un endpoint de callback estable continúan usando sondeo o SSE.

Pregunta de seguimiento 5: Un reporte genera un archivo de 20 GiB. ¿Debería la API de la operación devolver una URL de descarga directamente?

La operación debe devolver una referencia al recurso de resultado. Autorice al inquilino y al llamador nuevamente antes de emitir la credencial de descarga de 15 minutos seleccionada para este caso. No persista una URL de larga duración del almacén de objetos en la operación. El archivo vive durante 24 horas mientras que los metadatos de la operación viven durante 7 días, por lo que, tras la expiración del archivo, la operación aún puede indicar que la ejecución fue exitosa, que el artefacto expiró y que la regeneración está disponible.

Pregunta de seguimiento 6: El tráfico de consultas de estado supera al tráfico de ejecución. ¿Qué cambia primero?

Primero confirme que los clientes respeten Retry-After, el retroceso exponencial, un límite y la fluctuación. Luego habilite solicitudes condicionales basadas en ETag, cuotas de inquilino y limitación de tasa. Los navegadores que requieran menor latencia pueden consolidar las actualizaciones mediante SSE, y los llamadores de servidor pueden usar webhooks, mientras que las lecturas de estado de baja frecuencia siguen disponibles. Aplique fluctuación también al intervalo sugerido para que el pico de envíos de las 09:00 no se convierta en un pico periódico sincronizado en el endpoint de estado.

Fuentes públicas

Preguntas relacionadas