Cuándo el edge NO es la respuesta
Un modelo de ejecución que factura trabajo efectivo y reparte el cómputo por todo el planeta compra propiedades extraordinarias a cambio de tres renuncias muy concretas: no es el sitio para quemar procesador, no es el sitio para procesos que duran horas y no ofrece un Node completo con sistema de archivos, procesos hijos y extensiones nativas. Analizamos los tres síntomas, qué pieza recoge cada uno —Containers, Workflows y Queues, o directamente una máquina en una región— y por qué la arquitectura sana usa el edge como frontal universal y no como monolito universal.
Después de cuarenta niveles defendiendo el edge conviene cerrar con la lección que ninguna documentación de producto escribe: dónde termina. Un modelo que factura trabajo efectivo, arranca sin latencia de arranque en frío y ejecuta en cientos de ciudades compra esas propiedades a cambio de renuncias muy precisas, y la madurez técnica consiste en reconocerlas antes de estrellarse contra ellas. Hay exactamente tres formas de no encajar aquí, se detectan pronto si sabes qué mirar, y ninguna de ellas es un defecto de la plataforma: son la contrapartida del trato que aceptaste al elegirla.
- Reconocer los tres síntomas de una carga que no pertenece al edge.
- Distinguir el límite de
CPU timedel límite de duración y de las carencias de plataforma. - Elegir el destino correcto para cada síntoma:
Containers,Workflows, colas o una región. - Diseñar la frontera entre el frontal en el edge y el trabajo pesado de detrás.
Tres formas de no encajar
Las tres se pueden enunciar de una vez para tenerlas siempre a mano: cuánto procesador consume una sola petición, cuánto dura el trabajo completo y qué necesita del sistema operativo para funcionar. Casi cualquier carga que no encaje falla en al menos una de esas tres preguntas, y saber en cuál falla determina el destino, porque cada una tiene su propio remedio y ninguno sirve para las otras dos.
La primera es la CPU intensiva. Transcodificar vídeo, entrenar o ejecutar un modelo pesado en el propio proceso, renderizar imágenes complejas, comprimir archivos grandes, generar informes con millones de filas o hacer criptografía masiva son cargas cuyo coste es trabajo puro de procesador, exactamente lo único que aquí se factura y exactamente lo que el plan gratuito acota en 10 ms por petición. No es que sea imposible: es que estarías pagando la dimensión cara del modelo para hacer lo que una máquina dedicada hace mejor y más barato. El síntoma es inconfundible: el tiempo de respuesta y el consumo de CPU son casi el mismo número, porque no hay espera ninguna en medio.
Vale la pena descartar de entrada un espejismo recurrente. Compilar la parte pesada a WebAssembly mejora la constante —el mismo trabajo consume bastantes menos ciclos que en JavaScript— y por eso rescata casos que estaban en la frontera, pero no cambia la naturaleza del problema: el tiempo que consuma ese módulo sigue siendo tiempo de procesador facturado y sigue contando contra el mismo presupuesto. Sirve para que quepa lo que casi cabía; no sirve para que quepa lo que no cabe.
La segunda es la duración. Un Worker vive alrededor de una petición; no está pensado para sostener un proceso de horas, un trabajo por lotes nocturno que recorre una base entera, ni una ejecución que deba sobrevivir a despliegues y reinicios manteniendo su punto de avance. El síntoma aquí es distinto y más sutil: el código empieza a contener mecanismos artesanales para reanudar donde lo dejó —marcas de progreso en una tabla, banderas de si ya se hizo el paso tres— que son la reinvención pobre de un motor de flujos de trabajo.
Hay que subrayar que esta segunda restricción no es de coste sino de modelo. Un proceso de dos horas que solo espera consume una cantidad ridícula de procesador y sería baratísimo si pudiera existir; lo que no encaja es la idea de una ejecución que permanece viva, con su memoria intacta, a lo largo de despliegues, reinicios y traslados entre máquinas. Confundir ambas cosas lleva a la conclusión errónea de que basta con pagar más, cuando lo que hace falta es persistir el avance en algún sitio y dejar que la ejecución pueda morir sin llevarse el progreso por delante.
La tercera es la dependencia de plataforma. En 2026, nodejs_compat cubre un subconjunto amplio y muy útil de las APIs de Node, pero no existe un sistema de archivos real donde escribir, no hay procesos hijos que lanzar, no hay módulos nativos compilados que cargar y no hay servidor escuchando en un puerto. Una biblioteca que invoque un binario externo, que abra rutas del disco o que dependa de una extensión nativa no se arregla con configuración: pertenece a otro sitio. El síntoma es un error de importación o una llamada que devuelve algo que no existe, y la tentación de rodearlo con parches suele costar más que aceptar la frontera.
Esa tercera categoría tiene además dos parientes menores que conviene reconocer porque aparecen antes de lo que uno espera. Uno es el tamaño del bundle: hay un techo para el código desplegado, y las bibliotecas pensadas para un servidor suelen arrastrar dependencias enormes que no se justifican en un frontal. El otro es la memoria: un isolate no es el lugar donde cargar en un array un conjunto de datos de cientos de megabytes, y el patrón correcto para trabajar con volúmenes grandes es el flujo, no la carga completa. Ambos límites empujan en la misma dirección que el resto de la lección, hacia código que atraviesa datos en vez de acumularlos.
Un matiz importante, porque se confunde con frecuencia: que no exista un servidor escuchando en un puerto no significa que no haya red de bajo nivel. Existe la posibilidad de abrir conexiones salientes de tipo socket hacia servicios que hablan protocolos propios, que es lo que permite conectar con bases de datos que no exponen una interfaz por HTTP. La frontera real no está en el protocolo, está en el modelo de ejecución: puedes iniciar conversaciones hacia fuera, no puedes convertirte en un proceso que espera indefinidamente a que alguien se conecte.
flowchart TD A[la carga no encaja] --> B[el consumo es casi todo procesador] B -->|si| C[Containers o una region dedicada] B -->|no| D[dura mas que una peticion] D -->|si| E[Workflows colas o cron] D -->|no| F[necesita disco procesos o binarios] F -->|si| G[Containers o servidor tradicional] F -->|no| H[el edge si es el sitio] style H fill:#a6e3a1,color:#11111b style C fill:#f9e2af,color:#11111b style E fill:#89b4fa,color:#11111b style G fill:#f38ba8,color:#11111b
Son dos restricciones independientes y se resuelven de forma distinta. Un proceso que espera diez minutos a servicios externos gasta casi nada de procesador y choca contra la duración; un cálculo de treinta segundos sin una sola espera gasta treinta segundos de procesador y choca contra la CPU. El primero se arregla partiendo el trabajo en pasos durables; el segundo no se arregla partiéndolo, porque el trabajo total sigue ahí, y solo se resuelve moviéndolo a otro sitio.
Conviene además desconfiar de un cuarto síntoma falso, que es el más frecuente de todos: la carga que parece no encajar porque el código está mal repartido. Un endpoint que agota el presupuesto de procesador porque construye en memoria una respuesta de veinte megabytes no tiene un problema de plataforma, tiene un problema de paginación. Antes de concluir que algo pertenece a otro sitio hay que comprobar que el trabajo es realmente irreducible y no simplemente mal planteado, porque mudar un mal diseño a una máquina grande lo convierte en un mal diseño caro.
Dónde va cada carga
El error no es tener cargas que no encajan, lo tienen todos los sistemas reales. El error es forzarlas dentro, y el segundo error, más raro pero también costoso, es concluir a partir de una carga incómoda que la plataforma entera no sirve y devolverlo todo a un servidor. La plataforma ofrece destinos específicos para cada síntoma, y la elección se vuelve casi mecánica una vez identificado el síntoma correcto.
| Síntoma | Destino adecuado |
|---|---|
| Procesador saturado en una sola petición | Containers junto al edge, o una región dedicada |
| Trabajo que dura minutos u horas con esperas | Workflows con pasos durables |
| Ráfagas que deben absorberse y procesarse luego | Queues con un consumidor por lotes |
| Tarea periódica de mantenimiento | Cron con el manejador programado |
| Biblioteca que exige disco, puertos o binarios | Containers o servidor tradicional |
| Modelos de inferencia estándar | Workers AI, que ejecuta fuera de tu presupuesto de CPU |
| Consulta analítica sobre millones de filas | Un motor analítico detrás, consultado desde el frontal |
La fila de la inferencia ilustra un principio general que conviene extraer: cuando el trabajo pesado lo ejecuta un servicio dedicado, tu Worker vuelve a ser lo que mejor se le da, un coordinador que espera. Pedirle a un modelo que genere un texto consume, del lado de tu código, prácticamente nada de procesador, porque toda la carga ocurre al otro lado de la llamada. Ese patrón —delegar el cómputo intenso a quien lo tiene por oficio y quedarse con la orquestación— resuelve muchos más casos de los que parece a primera vista.
Antes de mudar nada conviene aplicar un filtro barato, porque una parte notable de las cargas que parecen no encajar en realidad no deberían existir. Un informe que recorre millones de filas por petición suele ser una consulta sin agregación previa; una imagen que se redimensiona al vuelo suele ser una imagen que podría haberse redimensionado al subirla; un cifrado masivo en la ruta crítica suele ser un cifrado que podía hacerse una vez y guardarse. Solo cuando el trabajo es irreducible tiene sentido buscarle otro sitio.
Containers merece un comentario porque es el destino que más malentendidos genera. No es una renuncia al edge ni un regreso al pasado: es una imagen que se ejecuta junto a la red de Cloudflare y a la que tu Worker invoca como invocaría a cualquier otro servicio, con la diferencia de que ahí sí hay sistema operativo completo, disco, procesos y todo el tiempo de procesador que quieras pagar. El patrón resultante es limpio: el Worker sigue siendo la puerta —autentica, valida, enruta, cachea— y delega el trabajo pesado en la imagen, que vive el tiempo que dure la tarea.
Esa división tiene un efecto colateral muy conveniente sobre la seguridad, y no siempre se aprovecha de forma consciente. La imagen que hace el trabajo pesado no necesita estar expuesta a internet: recibe únicamente peticiones que ya pasaron por el frontal, es decir, autenticadas, validadas y limitadas en ritmo. Reducir la superficie de ataque de la parte más frágil del sistema a un solo llamador conocido es una propiedad que en una arquitectura tradicional exige redes privadas y bastante configuración, y aquí sale casi gratis como consecuencia del reparto.
Hay un detalle de diseño que decide si esta delegación sale bien: el contrato entre el frontal y la pieza de detrás debe ser explícito y estrecho. Cuantos menos verbos exponga la parte pesada y más claros sean sus datos de entrada y salida, más fácil será cambiarla, reemplazarla o incluso eliminarla cuando el trabajo deje de ser necesario. Las delegaciones que envejecen mal son siempre las que empezaron pasando la petición entera y dejando que el otro lado decidiera qué hacer con ella.
Workflows recoge el segundo síntoma con una propiedad que ningún apaño artesanal iguala: cada paso se ejecuta como mucho una vez y su resultado queda persistido, de modo que un fallo reanuda desde el último paso completado en lugar de repetir todo. Entre pasos puede haber esperas de horas o de días sin que nadie pague tiempo de procesador por esperar, porque la ejecución se suspende de verdad.
Queues resuelve una variante distinta del mismo síntoma, y conviene no confundirlas. Un flujo de trabajo modela un proceso largo con pasos ordenados y estado propio; una cola modela muchos trabajos pequeños que llegan a un ritmo distinto del que se pueden atender. Cuando el problema es que un pico de tráfico produce más trabajo del que el sistema absorbe en ese instante, la cola actúa de amortiguador y el consumidor procesa por lotes, que además es el modo más barato de trabajar porque amortiza el coste fijo de cada invocación entre muchos mensajes.
Dejar fuera del edge algo que encajaba es un fallo caro pero visible: se nota en la latencia, en la factura de la máquina de al lado y en la complejidad del despliegue, y se corrige moviéndolo de vuelta. Meter dentro algo que no encajaba no produce un fallo, produce una deformación lenta que se manifiesta como troceados artificiales, marcas de progreso a mano y bibliotecas parcheadas. Por eso, ante la duda genuina, la asimetría recomienda empezar por el edge y estar dispuesto a mover, en lugar de forzar la permanencia.
export default {
async fetch(req: Request, env: Env) {
const trabajo = await req.json<{ documento: string }>();
// Lo pesado no se hace aqui: se delega y se responde de inmediato.
const id = await env.PROCESAR.create({ params: trabajo });
return Response.json({ estado: "aceptado", id: id.id }, { status: 202 });
},
} satisfies ExportedHandler<Env>;
Devolver un código de aceptación con un identificador de seguimiento, en vez de bloquear al cliente durante minutos, no es un rodeo para esquivar un límite: es el diseño correcto de cualquier operación larga, también en un servidor sin límite alguno. La restricción de la plataforma te empuja hacia la interfaz que un revisor exigente habría pedido de todas formas.
El edge como frontal, no como monolito
La arquitectura que resulta de todo lo anterior es estable y se repite en proyectos muy distintos: el edge es la puerta de todo y el ejecutor de casi todo, pero no de todo. En la puerta viven las tareas que se benefician de estar cerca del usuario y de costar poco: terminar la conexión, autenticar, validar, limitar el ritmo, enrutar, cachear, componer respuestas a partir de varias fuentes y servir assets. Es importante notar que esa lista no es un consuelo para lo que queda fuera: son, en casi cualquier sistema, la mayoría de las peticiones y la totalidad del tráfico de entrada. El edge no acaba siendo la parte pequeña del sistema por delegar lo pesado, sino justo al revés. Detrás viven las tareas que se benefician de una máquina: procesador sostenido, procesos largos, herramientas que exigen un sistema operativo entero.
Esa frontera tiene una propiedad que la hace especialmente valiosa y que conviene aprovechar de forma consciente: es una frontera de escala, no solo de capacidad. El frontal absorbe todo el tráfico del mundo, incluidos los picos y los ataques, y solo deja pasar hacia atrás el trabajo que de verdad requiere una máquina. El resultado es que la parte cara del sistema recibe un caudal filtrado, previsible y mucho menor que el bruto, y por tanto se dimensiona para lo que hace falta y no para el peor minuto del año.
Esa propiedad tiene una consecuencia económica que conviene explicitar, porque cierra el círculo con las lecciones anteriores: la pieza que se factura por tiempo encendido solo recibe el trabajo que de verdad exige tiempo encendido. Todo lo demás —los picos, los rastreadores, las peticiones repetidas, los assets, los errores de clientes mal programados— muere en el frontal, donde cuesta poco o nada. Repartir así no es solo una decisión técnica sobre dónde encaja cada carga; es la forma de que la parte cara del sistema sea también la más pequeña.
La frontera también aporta una ventaja organizativa que rara vez se menciona y que en equipos medianos pesa mucho: reduce la superficie del sistema que necesita operarse. Todo lo que vive en el frontal se despliega en segundos, no se dimensiona, no se parchea y no tiene servidores que vigilar; lo que queda detrás es un conjunto pequeño y bien delimitado de piezas que sí requieren atención. Esa asimetría concentra el esfuerzo operativo donde de verdad hace falta en lugar de repartirlo por todo el sistema.
Hay también una frontera intelectual que conviene enunciar: el edge es excelente para trabajo por petición y mediocre para trabajo por lote. Todo lo que se pueda expresar como responder rápido a un evento pequeño encaja de forma natural; todo lo que se exprese como recorrer un conjunto grande de una sola vez encaja mal, aunque a menudo pueda reescribirse como muchos eventos pequeños encolados, que es exactamente lo que hace una cola bien usada.
Esa reescritura merece intentarse antes de rendirse, porque el resultado suele ser mejor sistema y no solo mejor encaje. Un proceso por lotes que recorre una tabla entera cada noche falla entero cuando falla, va acumulando retraso conforme crece el conjunto y concentra toda su carga en una hora concreta. El mismo trabajo expresado como un evento por elemento falla por elemento, se reintenta por elemento, reparte la carga en el tiempo y observa su progreso con precisión. La restricción de la plataforma empuja hacia un diseño que, en igualdad de condiciones, cualquiera habría preferido.
Y queda una última cautela, que es la más difícil de aplicar porque exige honestidad con uno mismo: la frontera se traza con la carga que tienes, no con la que temes tener. Diseñar hoy una arquitectura repartida entre el edge y una máquina porque algún día habrá que generar informes pesados es tan costoso como el error contrario, ya que introduce dos sistemas, dos despliegues y un contrato entre ambos para resolver un problema que aún no existe. Empezar entero en el edge y mover la pieza el día que el síntoma aparezca es casi siempre la secuencia correcta, porque para entonces sabrás exactamente qué mover y por qué.
Procesador saturado
Si el tiempo de respuesta y el de CPU coinciden, no hay espera y por tanto el edge no te está regalando nada.
Mas largo que una peticion
Cuando el código empieza a guardar por dónde iba, lo que falta es un motor de flujos, no otro parche.
Puerta universal
Aunque el trabajo viva detrás, la entrada sigue siendo el edge: autentica, cachea y filtra el caudal.
Existe una fase, en la adopción de cualquier tecnología potente, en la que el entusiasmo empuja a resolverlo todo con ella; es una fase natural y hasta productiva, porque explorar los límites enseña más rápido que respetarlos de oídas, pero prolongarla produce sistemas frágiles y equipos incapaces de justificar sus decisiones ante alguien que pregunte por qué. El edge invita especialmente a esa fase porque casi todo funciona: puedes generar un PDF en un Worker, puedes recorrer una tabla enorme, puedes escribir tu propio motor de reintentos, y durante un tiempo nada explota. Lo que hay que entender es que la pregunta correcta nunca fue si se puede, sino si el trato que ofrece la plataforma tiene sentido para esa carga concreta. El trato es explícito y perfectamente razonable: renuncias a un sistema operativo, a un proceso de larga vida y a la posibilidad de quemar procesador sin pensar, y a cambio recibes ejecución en cientos de ciudades, ausencia de latencia de arranque en frío, coste proporcional al trabajo efectivo y espera gratuita. Ese trato es maravilloso para código que coordina y pésimo para código que muele, y ambas categorías conviven en todo sistema real, de modo que la pregunta nunca es cuál de las dos plataformas elegir sino dónde poner la frontera entre ellas. Poner esa frontera bien es una decisión de arquitectura de primer orden, y tiene una asimetría interesante: si dejas fuera del edge algo que encajaba, pagas latencia y complejidad innecesarias, lo cual es un error caro pero visible y reversible; si metes dentro algo que no encajaba, el sistema no falla, se deforma, y esa deformación aparece como una acumulación de apaños que nadie recuerda haber decidido —marcas de progreso a mano, troceados artificiales, bibliotecas parcheadas— hasta que reescribir cuesta más que haber elegido bien. Saber decir esto no va aquí es, por eso, un signo de dominio mayor que saber implementarlo todo dentro, porque exige haber entendido no solo cómo funciona la herramienta sino qué renunció para funcionar así.
- Enumera tres cargas de un proyecto tuyo y clasifica cada una en procesador, duración o dependencia de plataforma.
- Explica por qué partir en trozos un cálculo de treinta segundos de CPU no resuelve el problema y partir un proceso largo sí.
- Reescribe una operación bloqueante como aceptación diferida con identificador de seguimiento.
- Busca en tu código un mecanismo artesanal de reanudación y sustitúyelo mentalmente por pasos durables.
- Argumenta qué parte de tu sistema debe seguir en el edge aunque el trabajo pesado se mude, y qué protege esa decisión.