Planteamiento y contexto
Usted es el responsable de POST /exports para una exportación de gran tamaño. La solicitud valida la entrada e inicia el trabajo, pero la exportación puede tardar minutos. El entrevistador le pregunta si debe devolver 200, 201 o 202, y cómo un cliente se entera del resultado final.
Asuma que el servidor puede persistir un registro de exportación y encolar el trabajo. El cliente puede experimentar un timeout y repetir la solicitud. La respuesta debe definir el contrato, no solo nombrar un código de estado.
Qué evalúa el entrevistador
- Si distingue entre "recurso creado" y "solicitud aceptada para su procesamiento posterior".
- Si modela un recurso de estado durable, estados terminales y detalles de errores.
- Si un reintento puede crear dos exportaciones o perder la respuesta original.
- Si la cola y la actualización de la base de datos son confiables sin fingir la existencia de una transacción distribuida.
Preguntas aclaratorias antes de responder
- ¿El POST crea de inmediato un recurso de exportación durable? Si es así,
201 Createdpuede describir ese recurso; si no,202puede acusar recibo de un trabajo aceptado. - ¿Se puede reintentar la misma solicitud lógica? En caso afirmativo, exija una clave de idempotencia o un ID de operación proporcionado por el emisor de la llamada.
- ¿El cliente necesita sondeo (polling), webhooks o ambos? Esto modifica la representación del estado y el contrato de notificación.
- ¿Cuáles son las reglas de retención y autorización para los archivos exportados? Un trabajo completado no otorga permiso para exponer su resultado a cualquier emisor de llamadas.
Estructura de respuesta en 30 segundos
"Devuelvo 202 Accepted solo cuando el procesamiento se difiere y el resultado final no está listo. Primero creo un registro de trabajo durable, y luego devuelvo su URI de estado y un identificador de operación. El cliente consulta periódicamente ese URI con retroceso (backoff) o recibe una retrollamada (callback) autenticada. Una clave de idempotencia mapea los reintentos al mismo trabajo y respuesta. El trabajo transita por estados explícitos como en cola (queued), en ejecución (running), exitoso (succeeded) y fallido (failed); el worker y la bandeja de salida (outbox) son reintentables, y el endpoint de estado se mantiene como la fuente de la verdad".
Análisis detallado paso a paso
1. Elija el estado a partir del ciclo de vida del recurso
200 OK significa que la solicitud se completó con una representación. 201 Created significa que se creó un recurso y debe ser identificable. 202 Accepted significa que la solicitud fue aceptada, aunque el procesamiento puede no haber comenzado o finalizado; no promete un éxito eventual.
Si el registro de exportación se crea de forma síncrona y es el recurso que gestionará el emisor de la llamada, puedo devolver 201 con ese recurso. Si la API solo acusa recibo del trabajo y el resultado está pendiente, 202 junto con un URI de monitoreo es más claro. La elección depende del ciclo de vida observable, no del hecho de que casualmente exista una cola.
2. Haga que la respuesta sea procesable
Devuelva un ID de operación, una URL de estado y una representación con state, marcas de tiempo y una indicación de reintento segura. Una respuesta mínima puede verse así:
HTTP/1.1 202 Accepted
Location: /exports/exp_123
Retry-After: 5
Content-Type: application/json
{"id":"exp_123","state":"queued","status_url":"/exports/exp_123"}El recurso de estado debe aplicar autorización en cada lectura. queued y running son no terminales. succeeded incluye una referencia de descarga de corta duración; failed incluye un código de error estable y una sugerencia de remediación sin filtrar trazas de la pila (stack traces). El cliente debe tolerar la desaparición del recurso después de su periodo de retención.
3. Haga que los reintentos converjan
Exija Idempotency-Key para las operaciones que generan trabajo. Persista un hash de la solicitud relevante, el ID del trabajo resultante y el estado de la respuesta. Una clave repetida con la misma solicitud devuelve el resultado original; la misma clave con una solicitud diferente es un error del cliente. No utilice una ventana de tiempo por sí sola como regla de identidad, porque un reintento tardío puede llegar después de dicha ventana.
La API aún puede aceptar dos claves distintas para dos exportaciones. La idempotencia evita el trabajo duplicado para una misma operación lógica; no hace que los workers ejecuten exactamente una sola vez de forma inherente.
4. Cierre la brecha entre la base de datos y la cola
Escriba la fila de exportación y un evento de outbox en una única transacción de base de datos. Un retransmisor (relay) publica las filas pendientes del outbox y las marca como entregadas después de que el broker acusa recibo de ellas. Una falla del sistema (crash) puede volver a publicar el mismo evento, por lo que el consumidor utiliza el ID de exportación como clave de idempotencia. Esto preserva la invariante de que un trabajo confirmado (committed) sea eventualmente descubrible sin pretender que la base de datos y el broker se confirmen atómicamente.
El worker actualiza el estado mediante transiciones condicionales, por ejemplo queued -> running -> succeeded|failed. Un reintento obsoleto no puede hacer retroceder succeeded a running. Las métricas deben exponer la antigüedad en la cola, el tiempo en ejecución, la tasa de fallas terminales y el retraso del outbox.
5. Defina el sondeo, las retrollamadas y la cancelación
El endpoint de estado admite ETag o una versión para que el sondeo pueda utilizar solicitudes condicionales. Los clientes aplican un retroceso exponencial con una sugerencia del servidor y detienen el sondeo tras alcanzar un estado terminal. Los webhooks son una optimización, no la única forma de conocer el resultado: la entrega puede fallar, por lo que el cliente debe conciliar consultando el recurso de estado.
La cancelación es un comando separado, como POST /exports/exp_123/cancel. Solo se acepta para estados cancelables y es idempotente en sí misma. Un trabajo que ya ha alcanzado succeeded no puede revertirse mediante una cancelación tardía.
Respuesta de muestra de alta calidad
Primero preguntaría si el registro de exportación es un recurso creado por esta llamada. Si es así, podría devolver 201 y el registro. Para una operación diferida cuyo resultado no está listo, devuelvo 202 con un ID de operación y una URL de estado autenticada. Exijo una clave de idempotencia, almaceno la huella digital (fingerprint) de la solicitud y el ID del trabajo, y devuelvo la misma representación ante un reintento.
La transacción escribe la fila de exportación y un evento de outbox conjuntamente. Un relay y un consumidor idempotente gestionan la entrega al menos una vez (at-least-once). La máquina de estados del estado es monotónica: en cola, en ejecución, y luego exitosa o fallida. El cliente sondea con solicitudes condicionales y backoff; un webhook es solo un acelerador. Publico la antigüedad en cola, el retraso del outbox y los errores terminales, y defino la retención, la autorización, la expiración de descargas y la cancelación por separado. 202 acusa recibo de la aceptación, no del éxito.
Errores comunes
- Error: Tratar
202como prueba de que el trabajo tendrá éxito → Por qué falla: la semántica del RFC permite que el procesamiento falle o nunca comience → Solución: exponer el comportamiento ante fallas terminales y la retención. - Error: Devolver solo
202sin una URL de monitoreo → Por qué falla: los clientes no pueden descubrir el estado sin adivinar → Solución: devolver un recurso de estado autenticado y un ID de operación. - Error: Depender de una publicación en la cola después de la confirmación (commit) en la base de datos → Por qué falla: una caída del sistema crea un trabajo que ningún worker puede ver → Solución: utilizar un outbox transaccional y un relay reproducible.
- Error: Asumir que una cola proporciona una ejecución de exactamente una vez (exactly-once) → Por qué falla: los reintentos y las caídas pueden duplicar la entrega → Solución: hacer que los consumidores sean idempotentes y las transiciones condicionales.
- Error: Permitir que cada reutilización de clave de idempotencia devuelva éxito → Por qué falla: una clave puede ocultar una solicitud modificada → Solución: comparar la huella digital de la solicitud y rechazar las discrepancias.
Preguntas de seguimiento y respuestas
¿Debería este endpoint devolver 201 en su lugar?
Devuelva 201 cuando la llamada síncrona crea un recurso de exportación durable y puede identificarlo con Location. Devuelva 202 cuando el resultado significativo es diferido y la respuesta solo acusa recibo de la aceptación. Algunas API pueden usar 201 para el recurso del trabajo mientras siguen exponiendo un estado pendiente; documente qué recurso describe el estado.
¿Qué pasa si el cliente nunca realiza el sondeo?
Mantenga el estado del trabajo durable durante el periodo de retención documentado, envíe un webhook autenticado opcional y permita una posterior consulta GET mediante el ID de operación. La falla de una retrollamada no debe eliminar la única vía de acceso al estado. Las URL de descarga caducadas y las comprobaciones de autorización continúan aplicándose cuando el cliente regresa días después.
¿Puede el worker actualizar el trabajo dos veces?
Sí, la entrega normalmente es de al menos una vez (at-least-once). Utilice un ID de exportación único, transiciones de estado condicionales y escrituras de salida idempotentes. Un evento succeeded duplicado no debería causar daño; una transición desde un estado terminal de regreso a running debe rechazarse y registrarse.