Tema representativo de entrevista

Entrevista de backend: ¿Por qué un desfase de timeout entre Node y NGINX puede devolver un error mientras el trabajo se completa?

BackendIntermedio
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Un servicio de Node se encuentra detrás de un proxy inverso NGINX. El endpoint devuelve ocasionalmente un error 502, pero los logs de la aplicación muestran que el trabajo se completa segundos después. ¿Cómo localizaría la capa del timeout y elegiría entre modificar los timeouts, transmitir una respuesta por streaming o mover el trabajo a una cola?

Planteamiento y alcance

Un endpoint de Node realiza varias llamadas externas y normalmente tarda entre 5 y 35 segundos. Node permite 60 segundos, mientras que NGINX mantiene su valor predeterminado proxy_read_timeout. Los usuarios en producción ven ocasionalmente errores 502; el log de la aplicación indica más tarde que la escritura de negocio se completó. Bajo carga, las conexiones de larga duración también consumen el pool.

Dibuje una línea de tiempo para el cliente, NGINX, Node, las dependencias downstream y el almacenamiento de trabajos. Explique el origen del 502, por qué el trabajo puede finalizar después de que el cliente vea un fallo y cuándo usar una respuesta síncrona, streaming o una cola asíncrona. Los números son suposiciones de entrevista; la habilidad central radica en la semántica de timeouts entre capas, la cancelación, los límites de efectos secundarios, el aislamiento y la validación de la solución, por lo que esta es una pregunta de backend.

Qué evalúa el entrevistador

Los candidatos sólidos distinguen entre el cierre de conexión, el deadline de la aplicación y la finalización de negocio en lugar de reintentar cada 502. Saben que el read timeout de NGINX mide el tiempo de inactividad entre lecturas del upstream, no necesariamente la respuesta completa, y que AbortSignal.timeout() solo notifica a las operaciones que realmente escuchan la señal.

También hacen un inventario de los valores predeterminados en proxies, gateways, balanceadores de carga, SDKs y clientes; desacoplan las solicitudes HTTP de los trabajos largos cuando corresponde; y demuestran que la corrección no genera escrituras duplicadas, fugas de conexiones ni amplificación de reintentos.

Preguntas para aclarar primero

  • ¿El 502 es generado por NGINX o es devuelto por Node y reescrito? Compare encabezados, logs de error del proxy y logs de acceso hacia el upstream.
  • ¿Se confirmó un efecto secundario de negocio cuando ocurrió el timeout? Un resultado desconocido no se puede reintentar a ciegas.
  • ¿Debe devolverse el resultado en esta misma solicitud? Si solo importa el resultado final, una conexión síncrona de 35 segundos es innecesaria.
  • ¿El upstream está enviando bytes continuamente? El timeout de inactividad de lectura y el deadline total de la solicitud tienen significados diferentes en ese caso.
  • ¿La cancelación llega a la base de datos, al cliente HTTP y al SDK externo? Cerrar una conexión de navegador no detiene todas las operaciones.
  • ¿Cómo cambian la concurrencia, el uso del pool de conexiones, el retraso del event loop y la profundidad de la cola? Confirme el cuello de botella antes de cambiar los valores.

Una respuesta de 30 segundos

“Correlacionaría un trace ID único entre el cliente, NGINX, Node, las llamadas downstream y el almacenamiento para identificar qué capa emite el 502 y en qué momento. El proxy_read_timeout de NGINX limita el tiempo de inactividad entre lecturas; la configuración de solicitud de 60 segundos de Node no garantiza que un trabajo se detenga después de que el cliente se desconecte. Para un resultado síncrono, definiría un único deadline de extremo a extremo y dejaría un margen de limpieza entre el proxy, la aplicación y el downstream. Si el trabajo excede el presupuesto de interacción, se persiste, se devuelve un ID y se deja que un worker lo ejecute. Inyectaría fallos para verificar que no haya efectos secundarios duplicados, agotamiento de conexiones ni amplificación de reintentos.”

Solución paso a paso

Comience con la línea de tiempo. El cliente envía una solicitud, NGINX la reenvía y Node comienza a trabajar. Si Node no envía bytes de respuesta durante suficiente tiempo, el temporizador de lectura de NGINX puede expirar y cerrar la conexión con el upstream, produciendo un 502 o 504. Es posible que Node no reciba la cancelación en ese mismo instante; tal vez ya haya confirmado una escritura y luego termine el procesamiento. Por lo tanto, un fallo visible para el usuario y una operación de negocio completada pueden coexistir.

Correlacione los logs de acceso/error de NGINX, los eventos de inicio/fin/cancelación de solicitudes de Node, las llamadas downstream y los commits de base de datos utilizando trace IDs, request IDs y job IDs. Compare upstream_response_time, la duración del handler, la hora de recepción del cliente y la hora de confirmación del efecto secundario. Esto distingue el timeout de inactividad del proxy, el deadline de la aplicación, el timeout downstream y la desconexión del cliente. Un log de “éxito” en la aplicación por sí solo es insuficiente.

El proxy_read_timeout de NGINX tiene un valor predeterminado de 60 segundos y mide el intervalo de inactividad más largo entre dos lecturas; recibir bytes reinicia ese intervalo. Aumentarlo cambia la tolerancia del proxy, no los deadlines del cliente ni el costo de la conexión. Si lo cambia, registre los límites del proxy, de la aplicación y del cliente en una sola tabla y reserve tiempo para la transmisión de la respuesta, la limpieza y la fluctuación de red.

Node puede crear un deadline con AbortSignal.timeout() y pasar la señal a fetch, base de datos o llamadas de SDK que admitan cancelación. La cancelación es cooperativa: una librería que ignore la señal puede continuar. Una transacción ya confirmada no puede desaparecer mediante una cancelación. Por lo tanto, cada efecto secundario necesita una clave de idempotencia, una máquina de estados o una ruta de compensación con estados explícitos como accepted, running, succeeded, failed y unknown.

Si el p99 del trabajo está muy por encima del presupuesto de interacción, cree un límite asíncrono. La API valida la entrada, escribe un registro de trabajo o un mensaje en la cola y devuelve 202 junto con un ID de trabajo. Un worker toma el trabajo en concesión, ejecuta los reintentos y persiste el resultado; el cliente sondea o se suscribe al estado. La creación y finalización del trabajo deben ser idempotentes, los reinicios del worker deben ser recuperables y la entrega duplicada no debe duplicar pagos ni creación de recursos. La cola agrega almacenamiento, workers y operaciones de dead-letter que requieren capacidad y alertas.

El streaming es adecuado únicamente cuando los resultados pueden generarse de forma segura en fragmentos, todos los intermediarios admiten respuestas de larga duración y la duración total está delimitada. Los heartbeats no reemplazan un deadline total, un límite de salida o una vía de cancelación. No utilice el streaming para ocultar un trabajo no delimitado.

Verifique la corrección configurando un timeout de inactividad conocido en el proxy e inyectando silencio en el downstream más allá de ese límite; desconecte clientes en diferentes fases; reinicie workers; y ejecute pruebas de concurrencia. Compruebe que haya como máximo un efecto secundario exitoso por trabajo lógico, ningún reintento más allá del deadline, un uso delimitado de conexiones y colas, y una traza que reconstruya las marcas de tiempo de cada capa.

Respuesta modelo

“No empezaría cambiando de 30 segundos a cinco minutos. Primero correlacionaría las marcas de tiempo de NGINX, Node, downstream y base de datos para determinar si el proxy generó el 502 o si Node lo devolvió. proxy_read_timeout es un intervalo de inactividad entre lecturas, mientras que el deadline de solicitud de Node y la finalización de negocio son eventos separados; el proxy puede cerrar la conexión mientras Node continúa y confirma un efecto secundario.

Para un resultado síncrono, definiría un único deadline de extremo a extremo, propagaría el presupuesto restante hacia el downstream, utilizaría AbortSignal.timeout() y verificaría que cada SDK observe la cancelación. Un resultado de escritura desconocido requiere una clave de idempotencia y una consulta de estado. Si el p99 del trabajo excede el presupuesto de interacción, la API debe persistir el trabajo y devolver 202 con un ID; los workers ejecutan, reintentan y persisten el estado. Inyectaría timeouts de inactividad del proxy, desconexiones de clientes, reinicios de workers y entregas duplicadas, comprobando luego la ausencia de efectos secundarios duplicados, el uso acotado de conexiones y una traza completa.”

Errores comunes

  • Aumentar únicamente el timeout de NGINX → las conexiones largas y la presión de concurrencia persisten → defina un deadline de negocio y un límite asíncrono.
  • Reintentar cada 502 → el trabajo original puede haber sido confirmado → consulte el estado y reutilice una clave de idempotencia.
  • Tratar proxy_read_timeout como tiempo total de respuesta → fragmentos pequeños y continuos pueden mantener viva una solicitud indefinidamente → agregue un deadline total y un límite de salida.
  • Asumir que el cierre del cliente detiene a Node → muchas librerías ignoran la cancelación → verifique el comportamiento de abort, conexión y transacción en cada capa.
  • Usar heartbeats para ocultar un trabajo no acotado → los recursos aún se fugan → limite el tiempo total, los bytes y la concurrencia.
  • Ejecutar un trabajo de 35 segundos en un handler síncrono → las conexiones HTTP absorben todo el trabajo → persista el trabajo y use workers.
  • Mirar únicamente los logs de Node → los errores y tiempos del proxy se pierden → recopile accesos/errores del proxy y tiempos de upstream.
  • Agregar una cola sin estado idempotente → la entrega duplicada causa cobros duplicados → use una clave de trabajo única y actualizaciones de estado condicionales.

Preguntas de seguimiento y respuestas

Pregunta de seguimiento 1: ¿Es suficiente cambiar proxy_read_timeout a 60 segundos?

No. Solo controla el tiempo de inactividad entre lecturas; otra capa puede tener un deadline más corto y la conexión sigue consumiendo recursos. Defina primero el presupuesto de interacción y luego alinee cada capa.

Pregunta de seguimiento 2: ¿Cómo se detiene Node después de que un cliente se desconecta?

Observe el evento de cierre de la solicitud, cancele un controlador y pase su señal a operaciones cancelables. Para llamadas no cancelables, aísle la capacidad y descarte los resultados tardíos de forma segura. Los efectos secundarios confirmados aún requieren idempotencia y reconciliación.

Pregunta de seguimiento 3: ¿Cuándo es adecuado el streaming?

Cuando los resultados se pueden fragmentar de forma segura, todos los intermediarios admiten respuestas de larga duración y la duración total está delimitada. Mantenga un intervalo de heartbeat, un deadline total, un límite de salida y una ruta de cancelación.

Pregunta de seguimiento 4: ¿Cómo evita una cola la ejecución duplicada?

Derive una clave de trabajo a partir de la solicitud de negocio y aplique unicidad en el almacenamiento. Los workers usan leases, la finalización usa actualizaciones condicionales y los efectos secundarios externos reutilizan la misma clave de idempotencia.

Pregunta de seguimiento 5: ¿Cómo demuestra que la reparación funciona?

Inyecte timeouts de inactividad en el proxy, respuestas lentas del downstream, desconexiones de clientes, reinicios de red y reinicios de workers en staging. Compare las marcas de tiempo de las capas e inspeccione el origen del error, el uso de conexiones, los efectos duplicados y el retardo en la cola.

Pregunta de seguimiento 6: ¿Por qué los logs de la aplicación pueden decir éxito mientras el usuario recibe 502?

Es posible que el proxy haya cerrado la conexión primero, o que la respuesta se haya perdido después. Un log de finalización demuestra que el código terminó, no que la respuesta fue entregada. Correlacione el estado del proxy, el resultado de escritura en Node y lo observado por el cliente.

Pregunta de seguimiento 7: ¿Qué costo tiene la ejecución asíncrona?

Agrega almacenamiento de estados, workers, reintentos, colas dead-letter y consistencia eventual. A cambio, el tiempo de vida de HTTP se desacopla de la duración del trabajo y la concurrencia y la repetición se pueden controlar de forma independiente.

Fuentes públicas

Preguntas relacionadas