Segundos de trabajo, horas de residencia
Mi informe matutino empezó a fallar. Ollama estaba activo y devolvía un HTTP 500, porque una renderización de imagen de 21 segundos seguía ocupando 6.6 GB de VRAM horas después.
Dos mañanas seguidas, mi observador local produjo un briefing parcial y registró que el modelo de lenguaje no estaba disponible. Ollama estaba corriendo. El servicio estaba saludable. Todas las revisiones indicaban que el stack estaba bien.
Retornó un HTTP 500 porque el modelo necesitaba 14,191 MiB y la tarjeta tenía 124 MiB libres.
Una GPU, varios tenants
Una sola 3090 hospeda todo aquí: el LLM local que escribe el briefing, un reranker cross-encoder, un worker residente para la pipeline de contenido y generación de imágenes para posts sociales. La mayoría del tiempo esto está bien, porque la mayoría son pequeños o bursty.
Dos cosas no estaban bien.
La primera fue un trabajo nocturno que se extendió hasta el día laboral — un trabajo en cola por un scheduler hereda un presupuesto de duración fresco, no la ventana de tiempo restante, así que una tarea que debía terminar antes del amanecer corrió cuatro horas dentro de la mañana. Ya había arreglado eso y verificado que se mantuviera.
La segunda fue la interesante.
Veintiún segundos de trabajo, todo un día de residencia
El scheduler de contenido renderiza cards y carruseles a través de un servidor local de difusión. El render tarda unos 21 segundos y usa unos 6.6 GB. Luego termina, registra un alegre "0 modelos descargados", y mantiene la VRAM.
Segundos de trabajo. Horas de residencia. Y porque el trabajo tuvo éxito, nada reportó problema en ninguna parte — el único síntoma fue que otro servicio, horas después, falló al no encontrar espacio.
Hay un detalle de nombres que me gusta aquí, porque es el mismo defecto que sigo encontrando: el timer se describe como planeando el contenido del día, el servicio se describe como publicando contenido programado, y lo que realmente hace es generar en la GPU. Nada en el nombre sugería que fuera un tenant de GPU. Si me hubieras preguntado qué unidades competían por la tarjeta, no lo habría listado.
Arreglando el segundo: dos cambios, ambos sobre devolver memoria
Ninguno de estos es el arreglo del trabajo nocturno, que ya estaba hecho. Ambos abordan el servidor de render residente.
Libera lo que ya terminaste. El scheduler ahora llama al endpoint free del servidor de difusión al salir, protegido para que la cola esté vacía y nunca pueda descargar modelos mientras un trabajo sigue corriendo. No es fatal y preserva el código de salida original — una publicación nunca debe fallar porque una liberación de memoria falló.
Deja de reservar lo que nunca usas. El observador estaba pidiendo una ventana de contexto de 32k para un prompt que mide unos 7.6k tokens, lo que reservaba una caché key-value de 5,440 MiB que nunca tocaría. Reducir a la mitad el contexto bajó la caché a 2,720 MiB y el requerimiento total de 14,191 MiB a 11,327 MiB — y movió el modelo de 37 de 41 capas en la GPU a las 41.
El segundo arreglo es el que vale la pena internalizar. No agregué memoria ni removí un tenant. Dejé de reservar memoria basándome en un valor por defecto que nunca cuestioné. El peor caso realista diurno ahora cabe con espacio de sobra incluso si el primer arreglo nunca se activa.
El mensaje de error mentía, pero con cortesía
Antes de todo esto, el briefing registró el modelo como "inaccesible". No estaba inaccesible. Respondió inmediatamente, con una negativa.
Esos son problemas diferentes con arreglos diferentes, y colapsarlos en una sola palabra me costó toda la primera mañana. "Inaccesible" te manda a revisar redes, puertos y si el contenedor está arriba. "Negado" te manda a revisar qué se pidió. Cambié la etiqueta la misma semana que cambié la memoria.
Una cadena de error es un diagnóstico, y un diagnóstico erróneo en un log es peor que no tener diagnóstico, porque lo crees.
Escrito por
Adrian Romo
Ingeniero Backend Senior que diseña APIs escalables en Python, arquitecturas sobre AWS Lambda, sistemas de voz e integraciones empresariales.
Relacionado
Sigue leyendo
Seis publicaciones al día y el programador que aprendió a decir cuándo
Un pipeline social que publicaba un Reel al día y nada más, porque las cuotas por formato eran techos y nadie solicitaba los otros formatos.
¿Qué Merece Atención Hoy?
Mi homelab genera un veredicto cada mañana: algo te necesita, o nada lo hace. Conseguir que la segunda parte fuera honesta fue mucho más difícil que la primera.
La alerta que nombró algo y lo presentó como evidencia
Cinco alertas de alta severidad de mi propio monitoreo. Las cinco fueron por el mismo defecto: un registro que nombra algo se leía como una observación de una propiedad que nunca midió.
Continúa
¿A dónde sigues?
Explora más textos técnicos, revisa los casos de estudio o escríbeme directo.