El límite de tiempo de CPU
El límite que más confunde a quien llega del mundo de los servidores: no es cuánto tarda tu petición en total, sino cuánto trabaja de verdad el procesador. La espera de red no cuenta. Definimos con precisión qué es el CPU time frente al tiempo de reloj, repasamos los límites por plan —10 ms en Free, 30 segundos por defecto en Paid y hasta 5 minutos configurables—, y vemos cómo medirlo y qué hacer cuando lo excedes.
Quien llega desde un servidor tradicional trae grabada una intuición: si mi petición tarda treinta segundos, es que consumí treinta segundos de máquina. En Workers esa intuición es falsa y hay que desaprenderla. El límite que impone la plataforma no mide el tiempo que pasa desde que entra la petición hasta que sale la respuesta, sino solo los instantes en que el procesador está de verdad ejecutando tu código. Todo el tiempo que tu Worker pasa esperando la red es gratis y no cuenta. Entender esa distinción es entender el modelo de coste entero.
- Definir con precisión qué es el
CPU timey en qué se diferencia del tiempo de reloj de pared. - Saber qué operaciones consumen CPU y cuáles —la espera de entrada y salida— no consumen nada.
- Conocer los límites por plan y cómo subirlos con
cpu_mshasta cinco minutos. - Medir el consumo real de tu Worker y reaccionar cuando el error de límite aparece.
Qué cuenta como CPU y qué no
El CPU time es el tiempo que el procesador pasa ejecutando instrucciones de tu código: parsear JSON, recorrer un array, comprimir un buffer, calcular un hash, renderizar HTML. El tiempo de reloj de pared, en cambio, es el que mide un cronómetro colgado en la pared desde que llega la petición hasta que se va la respuesta, esperas incluidas.
La diferencia entre ambos es toda la espera de entrada y salida. Cuando tu Worker lanza un fetch(), una lectura de KV o una consulta a D1 y se queda aguardando la respuesta, el procesador no está trabajando para ti: cede el hilo y atiende a otros. Ese tiempo de espera puede ser enorme y no suma un solo milisegundo a tu CPU time.
export default {
async fetch(request, env, ctx): Promise<Response> {
// esto NO cuenta como CPU: es espera de red pura
const datos = await fetch("https://api.lenta.example.com/informe");
// esto SI cuenta: el procesador trabaja de verdad
const texto = await datos.text();
const filas = texto.split("\n").map((l) => l.split(","));
const total = filas.reduce((acc, f) => acc + Number(f[3]), 0);
return Response.json({ total });
},
};
En ese ejemplo, si la API tarda dos segundos en responder, esos dos segundos son tiempo de reloj pero no CPU. Lo que sí es CPU es partir el texto, mapearlo y sumarlo. Por eso un Worker puede vivir minutos esperando recursos lentos sin acercarse jamás a su límite, mientras que un bucle mal planteado sobre un millón de elementos puede fulminarlo en una fracción de segundo.
Cloudflare no pone un tope al tiempo de reloj de una petición mientras el cliente siga conectado: puedes esperar un backend lento sin que te corten. El trabajo que sobreviva a la desconexión del cliente, eso sí, se cancela salvo que lo entregues a ctx.waitUntil(), que lo extiende hasta treinta segundos más. El límite duro es el de CPU, no el del reloj.
Los límites por plan
El tope de CPU time es por invocación y depende del plan. En el plan Free son 10 milisegundos de CPU por invocación: suficiente para un endpoint que transforma y responde, insuficiente para trabajo pesado. En el plan Paid, el valor por defecto es de 30 segundos, un margen enorme que rara vez se toca si tu código no tiene un error.
Y si de verdad necesitas más —piensa en hashear un fichero grande traído de R2 o en un cálculo criptográfico intenso—, puedes subir el límite hasta cinco minutos, es decir, 300000 milisegundos, con una sola clave en el manifiesto.
{
"limits": {
// por defecto son 30000 (30 s); el maximo es 300000 (5 min)
"cpu_ms": 300000
}
}
El valor por defecto de 30 segundos no es tacañería, es una red de seguridad: te protege de que un bucle infinito accidental dispare tu factura antes de que te des cuenta. Subir cpu_ms es una decisión consciente que tomas cuando sabes que tu carga es legítimamente intensa. Puedes incluso bajarlo por debajo de 30 segundos para acotar el gasto de un Worker del que desconfías.
El tope de cinco minutos aplica a las peticiones HTTP. Un Cron Trigger o un consumidor de Queues admite hasta quince minutos de CPU por invocación, porque son cargas de fondo pensadas para durar. Y recuerda que estos límites solo se aplican en la red de Cloudflare: en desarrollo local con wrangler dev no se imponen, así que un Worker que va bien en tu máquina puede excederlos en producción.
Cómo medirlo y qué hacer al excederlo
Cuando tu Worker rebasa el límite, Cloudflare devuelve al cliente el error 1102, “Worker exceeded resource limits”. En el panel aparece como “Exceeded CPU Time Limits” bajo las estadísticas de invocación, y en analítica y Logpush el desenlace se marca como exceededCpu. Es una señal inequívoca: no es que el backend fuera lento, es que tu código trabajó demasiado.
flowchart LR
INV[Invocacion del Worker] --> CPU[Tiempo ejecutando codigo]
INV --> IO[Tiempo esperando red y almacenamiento]
CPU --> LIM{Supera el limite de cpu_ms}
IO --> FREE[No cuenta y no se cobra]
LIM -- si --> ERR[Error 1102 exceededCpu]
LIM -- no --> OK[Respuesta normal]
style CPU fill:#fab387,color:#11111b
style IO fill:#a6e3a1,color:#11111b
style ERR fill:#f38ba8,color:#11111b
style OK fill:#89b4fa,color:#11111bPara localizar de dónde sale ese consumo, el camino es el perfilado de CPU con las DevTools que Wrangler expone: te muestra un desglose por función y revela el punto caliente exacto, casi siempre un bucle, una deserialización enorme o una expresión regular patológica. Medir antes de optimizar evita reescribir la parte que no era el problema.
Si el trabajo es legítimamente pesado y aun así choca contra el techo, tienes tres salidas. La primera es optimizar: recortar el algoritmo, evitar copias, usar estructuras más baratas. La segunda es trocear: partir el cálculo en fragmentos que se reparten entre varias peticiones o pasos. La tercera es delegarlo a una pieza pensada para durar —Durable Objects, Queues o Workflows—, que es justo lo que veremos al cerrar este nivel.
Que la plataforma mida CPU y no tiempo de reloj no es un tecnicismo de facturación: es la consecuencia directa del modelo de isolates y la clave de por qué el edge puede ofrecer arranque en cero y densidad altísima. En un servidor que alquilas por horas, pagas el tiempo tanto si el procesador suda como si dormita esperando una base de datos; el recurso que reservas es la máquina entera, ociosa o no. En un isolate, miles de inquilinos comparten el mismo hilo y el mismo proceso ya caliente, y eso solo funciona si el reparto es justo: mientras tu Worker espera una respuesta de red, cede el procesador para que otro trabaje, y por eso esa espera ni te cuesta ni cuenta contra tu límite. Lo único escaso de verdad, lo único que de verdad le quitas a los demás, son los ciclos de procesador que consumes ejecutando tu código, y es exactamente eso lo que la plataforma mide y cobra. Interiorizar esta idea reordena cómo diseñas: dejas de temer las operaciones lentas —una consulta que tarda, una API remota perezosa— porque la lentitud de red es gratis, y empiezas a temer las operaciones densas —parsear megabytes, cifrar en bucle, recorrer estructuras gigantes— porque ahí es donde de verdad gastas el recurso compartido. El modelo premia al Worker que espera mucho y calcula poco, que resulta ser la forma natural de la inmensa mayoría del trabajo web. Cuando entiendes que pagas por trabajo real y no por tiempo reservado, dejas de optimizar cronómetros y empiezas a optimizar cómputo, que es la única pregunta que este modelo recompensa.
- Toma un Worker que llama a una API externa y transforma la respuesta: señala qué líneas consumen
CPU timey cuáles son espera de red que no cuenta. - Explica por qué un Worker puede tardar diez segundos de reloj en responder sin acercarse al límite de CPU, y qué tipo de código sí lo agotaría.
- Configura
cpu_msa un valor bajo a propósito y provoca el error 1102 con un bucle costoso; observa cómo aparece comoexceededCpu. - Usa el perfilador de CPU de las DevTools sobre ese bucle e identifica la función que concentra el gasto.
- Argumenta por qué el modelo de medir CPU y no tiempo de reloj es coherente con que miles de isolates compartan un mismo hilo.