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.

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:
- CPU time — nanos que el kernel/isolate te cuenta (Workers).
- Wall clock —
maxDuration/ timeout HTTP (Vercel, el cliente de Telegram). - 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 sí 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:
| RAM | Precio/s | Precio/h | Precio/mes |
|---|---|---|---|
| 256 MB | USD 0,00000078 | USD 0,0028 | USD 2,02 |
| 512 MB | USD 0,00000128 | USD 0,0046 | USD 3,32 |
| 1 GB | USD 0,00000228 | USD 0,0082 | USD 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

| Runtime | Reloj (docs 2026-09-03) | Qué cortar |
|---|---|---|
| Docker | --cpus (CFS quota) | loop local, no el fetch |
| Fly shared-cpu-1x | cobro por segundo | Machine size, no réplicas |
| Workers Free | 10 ms CPU / 128 MB | nada pesado en isolate |
| Workers Paid | 30 s default, 5 min techo | loop de tools; Error 1102 |
| Vercel Fluid Hobby | 300 s wall, 1 vCPU | número de tools por invocación |
Errores comunes

| Síntoma | Causa | Fix |
|---|---|---|
| Telegram timeout, modelo “rápido” | --cpus bajo + parse | más CPU o menos CPU work |
| Worker Error 1102 | CPU limit | Free→Paid o saca el parse |
| Function 504 | wall maxDuration | menos tools / cola |
| Railway caro | busy loop keep-warm | sleep / cron, no spin |
| “Subí RAM y sigue lento” | era CPU | mira docker stats |
Relación con el resto
- RAM: OOM.
- Cuántos procesos: concurrencia.
- Cortar el turno: SIGTERM.
- Apagar: kill switch.
Checklist
- Sabes si el p95 es wait-on-model o CPU local
- Docker tiene
--cpusescrito - 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.
Lecturas relacionadas
Sigue explorando Deploy y otras piezas para builders.



