Análisis en Habr: por qué r.Context() no detiene al LLM y cómo construir tareas de IA en Go
Habr ha publicado un análisis de una trampa habitual en los backends de Go que usan LLM. El esquema clásico cancela el trabajo junto con la petición HTTP a través de r.Context(). Pero si el usuario cierra la pestaña en mitad del análisis de un documento, el proveedor puede seguir generando y facturando los tokens. El autor propone sacar las operaciones de IA de larga duración a tareas en segundo plano sobre PostgreSQL. Además, recomienda trabajar por separado la idempotencia, los reintentos (retry) y la protección frente a cobros duplicados. • El contexto de la petición no equivale al ciclo de vida de la tarea de IA. • Conviene guardar el estado de la tarea en PostgreSQL, no en la memoria del proceso. • Un retry sin idempotencia significa pagar dos veces por la API.
Procesado por IA desde Habr AI; editado por Hamidun News
Cerrar la pestaña del navegador cancela la petición HTTP, pero no tiene por qué detener el modelo en el lado del proveedor. El autor de un reciente análisis en Habr muestra cómo esa diferencia se traduce en costes y bugs en un backend de Go corriente. Si un usuario lanza el análisis de un documento y se marcha, el servicio puede quedarse sin resultado y aun así recibir la factura por los tokens. Para las operaciones de IA de larga duración, el autor propone tareas en segundo plano sobre PostgreSQL, idempotencia estricta y una política de reintentos meditada.
Dónde se rompe el modelo habitual
Los desarrolladores de Go están acostumbrados a una regla sencilla: el trabajo vive mientras viva `r.Context()`. El cliente corta la conexión, el contexto se cancela, las goroutines terminan y los recursos se liberan. Para una consulta a la base de datos o a un microservicio interno, esto resulta cómodo y correcto.
Con los LLM todo es distinto. Una llamada puede durar decenas de segundos o incluso minutos, sobre todo al procesar documentos grandes o cadenas de varias llamadas al modelo. La tarificación se calcula por los tokens procesados y generados, y cancelar la petición por su parte no garantiza que el proveedor detenga el trabajo de inmediato. Depende de la API concreta y de cómo se cierre la conexión.
Surgen dos problemas a la vez:
- el trabajo se cancela, no hay resultado y el dinero ya se ha gastado;
- el usuario vuelve, pulsa el botón otra vez y la operación de pago se lanza de nuevo.
La tarea en segundo plano como entidad independiente
La idea central del análisis es que la operación de IA no debe pertenecer a la petición HTTP. El handler recibe la entrada, crea la tarea y responde enseguida con un identificador. A partir de ahí, la tarea sigue su propio curso y el cliente se entera de su estado mediante polling, SSE o WebSocket.
Como almacenamiento, el autor elige PostgreSQL. Para muchos equipos es una opción razonable: la base de datos ya está en el stack, las transacciones son bien conocidas y no hace falta un broker de mensajes aparte. Un conjunto típico para una cola de este tipo es el siguiente:
- una tabla de tareas con estado (creada, en ejecución, completada, error, cancelada);
- captura de tareas por parte de los workers mediante `FOR UPDATE SKIP LOCKED`, para que dos workers no tomen la misma;
- hora del último heartbeat, a partir de la cual las tareas colgadas vuelven a la cola;
- contador de intentos y hora del siguiente intento;
- resultado guardado y datos de los tokens consumidos.
La principal ventaja es que el estado sobrevive al reinicio del servicio. Si hay un despliegue o se cae un pod, la tarea no desaparece junto con la goroutine, sino que la recoge otro worker.
Idempotencia y dinero
El punto más caro de un sistema así está en la intersección entre retry y facturación. Repetir una petición a un LLM cuesta dinero, por lo que no se debe hacer a ciegas, como se repetiría una consulta a una caché.
Principios prácticos que se desprenden de la lógica del análisis:
- la clave de idempotencia se crea a nivel de la acción del usuario y protege frente a la doble pulsación del botón;
- la tarea tiene un identificador único, con el que el resultado se escribe una sola vez;
- el retry solo se permite para errores en los que repetir tiene sentido (timeout, 429, 5xx), pero no para entradas no válidas;
- el cobro al usuario se vincula a la tarea, no a cada intento;
- la cancelación por parte del usuario se convierte en un estado explícito, no en un efecto secundario de una conexión rota.
Por dónde empezar
Si en su servicio la llamada al LLM se ejecuta directamente en el handler, compruebe tres cosas. Primera: qué ocurre con la generación ya pagada si el cliente se desconecta a mitad. Segunda: si una petición repetida puede crear un duplicado de la operación de pago. Tercera: si la tarea sobrevivirá al reinicio del proceso.
Si la respuesta a al menos una de estas preguntas es incómoda, hace falta un modelo de tarea independiente. El paso mínimo es una tabla con estados y un solo worker; `SKIP LOCKED`, el heartbeat y la política de reintentos pueden añadirse a medida que crezca la carga. Tiene sentido incorporar un broker aparte cuando PostgreSQL deje de poder con la cola. Hasta entonces, por lo general, solo complica el sistema.
El material no trata de un nuevo modelo ni de un lanzamiento, sino de la disciplina de ingeniería en torno a los LLM. Ahí es donde ahora se pierde una parte notable de los presupuestos de los productos de IA: los errores aparecen en la infraestructura que rodea al modelo, no en los prompts.
❓ Preguntas frecuentes sobre la noticia
Dónde se rompe el modelo habitual?
Los desarrolladores de Go están acostumbrados a una regla sencilla: el trabajo vive mientras viva `r.Context()`. El cliente corta la conexión, el contexto se cancela, las goroutines terminan y los recursos se liberan. Para una consulta a la base de datos o a un microservicio interno, esto resulta cómodo y correcto. Con los LLM todo es distinto. Una llamada puede durar decenas de segundos o incluso minutos, sobre todo al procesar documentos grandes o cadenas de varias llamadas al modelo. La tarificación se calcula por los tokens procesados y generados, y cancelar la petición
¿Qué se sabe sobre La tarea en segundo plano como entidad independiente?
La idea central del análisis es que la operación de IA no debe pertenecer a la petición HTTP. El handler recibe la entrada, crea la tarea y responde enseguida con un identificador. A partir de ahí, la tarea sigue su propio curso y el cliente se entera de su estado mediante polling, SSE o WebSocket. Como almacenamiento, el autor elige PostgreSQL. Para muchos equipos es una opción razonable: la base de datos ya está en el stack, las transacciones son bien conocidas y no hace falta un broker de mensajes aparte. Un conjunto típico para una cola de este tipo es el siguiente: una
¿Qué se sabe sobre Idempotencia y dinero?
El punto más caro de un sistema así está en la intersección entre retry y facturación. Repetir una petición a un LLM cuesta dinero, por lo que no se debe hacer a ciegas, como se repetiría una consulta a una caché. Principios prácticos que se desprenden de la lógica del análisis: la clave de idempotencia se crea a nivel de la acción del usuario y protege frente a la doble pulsación del botón; la tarea tiene un identificador único, con el que el resultado se escribe una sola vez; el retry solo se permite para errores en los que repetir tiene sentido (timeout, 429, 5xx), pero
Access Frontier LLMs & Multimodal AI in One Workspace
Discover NomadNet AI (nomadnet.ai) — unified access to frontier language models, research synthesis, and multimodal workflows.
Lo esencial de la IA — una vez por semana
Siete historias que de verdad importaron, elegidas a mano. Sin ruido ni notas de prensa.
¡Listo! Revisa tu correo para la confirmación.