Guía9 min

Límites de CPU de un agente IA: cgroup, Workers y maxDuration

Resumen

Cómo no confundir RAM llena con CPU throttling: cpu shares de Docker, vCPU de Fly y Railway, 10 ms de Workers Free frente a 30 s Paid, y maxDuration de Vercel que corta el wall clock no el modelo. El 429 del proveedor no es un cgroup.

DockerCloudflareVercel
Proceso de agente contra un techo de CPU y un reloj de duración

Qué resuelve

Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.

El turno “se siente lento” y no es el modelo: el cgroup te da 0.25 vCPU y estás parseando un JSON de 20 MB. OOM es RAM. Concurrencia es cuántos procesos. Esta guía es cuánto CPU tiene uno. Fuentes oficiales consultadas el 3 de septiembre de 2026.

La regla

Tres relojes distintos:

  1. CPU time — nanos que el kernel/isolate te cuenta (Workers).
  2. Wall clockmaxDuration / timeout HTTP (Vercel, el cliente de Telegram).
  3. Quota del modelo — 429, no es tu box.

Si esperas 8 s en fetch a OpenAI, Workers no gasta esos 8 s de CPU (I/O no cuenta). Docker ocupa el proceso. No copies el diagnóstico.

Docker

Docs de resource constraints: --cpus="1.5" es un techo duro, equivalente a --cpu-period="100000" y --cpu-quota="150000" (periodo CFS por defecto 100000 µs). Sin --cpus, un loop de embeddings tumba el VPS. Con 0.25, el turno se estira y Telegram corta. Mide cpu en docker stats durante el tool, no en /health.

--cpu-shares default 1024 es peso relativo: “soft limit”, no reserva CPU. Docs: no garantiza acceso. Para un agente, --cpus es el flag honesto.

Fly / Railway

Pagas por segundo. Tabla de Machines (pricing, región default, consultada hoy), shared-cpu-1x:

RAMPrecio/sPrecio/hPrecio/mes
256 MBUSD 0,00000078USD 0,0028USD 2,02
512 MBUSD 0,00000128USD 0,0046USD 3,32
1 GBUSD 0,00000228USD 0,0082USD 5,92

Subir RAM no sube CPU. Si el p95 del turno es CPU-bound (parse, crypto, zip), cambia de shared-cpu-1x a más shared o performance; si es espera al modelo, no. Railway Hobby cobra uso: un while(true) de “keep warm” es factura, no latencia.

Workers

Limits (hoy): CPU time por HTTP request Free 10 ms, Paid 5 min (default 30 s, cpu_ms hasta 300000). Cron Trigger: Free 10 ms; Paid 30 s si intervalo < 1 h, 15 min si ≥ 1 h. Memoria 128 MB Free y Paid. Worker promedio ~2,2 ms. Error al pasarte: 1102 / exceededCpu. Un JSON.parse de dump o un loop de tools en CPU muere en Free aunque el fetch sea barato.

No metas PDF parse en el isolate. Págalo a un proceso con cgroup, o no lo hagas.

Vercel

maxDuration es wall, no CPU. Fluid (limitations, hoy): Hobby 300 s default y máximo. Pro/Enterprise 300 s default, 800 s máximo, 1800 s extended (beta). Memoria: Hobby 2 GB / 1 vCPU; Pro/Ent hasta 4 GB / 2 vCPU. Fluid reusa instancia; no te da más CPU mágico. Si 4 tools + modelo = 90 s, cabe en 300 s; si son 10 min, no. Parte el trabajo (graceful no alarga el Function).

Tabla

CPU time, wall clock y espera al modelo

RuntimeReloj (docs 2026-09-03)Qué cortar
Docker--cpus (CFS quota)loop local, no el fetch
Fly shared-cpu-1xcobro por segundoMachine size, no réplicas
Workers Free10 ms CPU / 128 MBnada pesado en isolate
Workers Paid30 s default, 5 min techoloop de tools; Error 1102
Vercel Fluid Hobby300 s wall, 1 vCPUnúmero de tools por invocación

Errores comunes

Turno lento por 0.25 CPU, no por el modelo

SíntomaCausaFix
Telegram timeout, modelo “rápido”--cpus bajo + parsemás CPU o menos CPU work
Worker Error 1102CPU limitFree→Paid o saca el parse
Function 504wall maxDurationmenos tools / cola
Railway carobusy loop keep-warmsleep / cron, no spin
“Subí RAM y sigue lento”era CPUmira docker stats

Relación con el resto

Checklist

  • Sabes si el p95 es wait-on-model o CPU local
  • Docker tiene --cpus escrito
  • Workers: el work cabe en 10 ms (Free) o lo sacaste
  • Vercel: tools × latencia < maxDuration
  • No hay loop de keep-warm
  • Ensayo: docker stats / métricas en un turno, no en idle

FAQ

¿Más réplicas? Duplican CPU bill, no aceleran un turno. Salvo cola de jobs.

¿GPU? El modelo está en la API. Tu box no necesita GPU para un bot de Telegram.

¿Priority CPU en Fly? Solo si mediste CPU-bound. Si no, es recargo.

Qué no es

No es una guía de “elige el modelo más barato”. El 429 del proveedor se trata en reintentos; aquí el techo es tu runtime. Tampoco es benchmark de laptops: mide el mismo binario en el cgroup de prod.

El ensayo: un turno con tool pesado vs uno que solo fetch. Si ambos duran igual, era el modelo. Si solo el pesado se alarga, era el cgroup.

No subas a 8 vCPU “por si el agente piensa más”. El pensamiento está en el proveedor. Tú pagas el glue. Un isolate de Workers Free no se vuelve “más listo” con un plan de Docker: o cabe en 10 ms de CPU o el trabajo no es de Worker.

En Vercel, 300 s de Hobby alcanzan un turno de 4 tools si cada fetch al modelo tarda 8 s. No alcanzan un batch de 40 tickets. Eso no se arregla subiendo a Pro por el techo de 800 s: se parte en cola. En Fly, el shared-cpu-1x a USD 0,00000228/s con 1 GB RAM sigue siendo un cuarto de core compartido; el precio mensual de USD 5,92 no compra un Ryzen.

Siguiente paso: si CPU ya cabe y igual se cae, healthchecks y logs. Sin runtime: curso.