Concurrencia y réplicas de un agente IA: cuándo no escalar
Resumen
Cómo no clonar el sqlite ni disparar 200 llamadas al modelo a la vez: Fluid Compute de Vercel, límites de Workers (128 MB, conexiones), fly scale count, réplicas en Railway y Compose. Un webhook no es un stateless API: la réplica extra a veces duplica el bot.

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.
Escalar un agente no es replicas: 3. Tres procesos con el mismo token de Telegram y el mismo sqlite son tres bots peleando. Cold start cubre el primer hit lento. Esta guía cubre cuántos procesos a la vez y qué se rompe si subes el número. Fuentes oficiales consultadas el 3 de septiembre de 2026.
Healthchecks dicen si una réplica está viva. Backup cubre el disco. Graceful shutdown cubre matar una. Aquí: cuántas dejas vivas.
La regla
Estado local (sqlite, cola en RAM, un solo webhook) → una réplica de escritura. Stateless (proxy al modelo + tools HTTP) → el proveedor escala solo. Tope de llamadas al modelo en vuelo, no de contenedores.
Si no puedes decir dónde vive el estado, no subas réplicas.
Vercel
Fluid Compute reusa la instancia entre requests: varias invocaciones pueden compartir un mismo proceso. No pones un número de réplicas; Vercel prioriza instancias idle antes de abrir otra. En limitations (Fluid, consultado hoy): memoria máxima 2 GB Hobby / 4 GB Pro y Enterprise; duración Hobby 300 s (default y techo); Pro 300 s default, 800 s máximo, 1800 s extendido (beta). La concurrencia automática llega a 30.000 en Hobby/Pro y 100.000+ en Enterprise.
Concurrency scaling (docs, 11 agosto 2026): el burst es 1.000 ejecuciones concurrentes / 10 s / región. Si lo pasas, 503 FUNCTION_THROTTLED. Un agente en Route Handler: cada request es un turno. No clones Functions a mano. El peligro no es “poca réplica”; es N webhooks en paralelo gastando la misma API key.
Pon un semáforo en proceso (inFlight < 4) o una cola. Fluid no te lo pone. El tope de plataforma es de invocaciones, no de llamadas al modelo.
Workers
Límites verificados en docs (Free vs Paid, 3 sep 2026): 128 MB de memoria en ambos, 6 conexiones salientes simultáneas por request, CPU 10 ms Free / hasta 5 min Paid (default 30 s). Startup 1 s. No hay fly scale count: Cloudflare aísla por request. Un Worker no es un daemon de 3 réplicas.
Si necesitas un solo hilo de trabajo (un sqlite, un lock de chat), usa una cola (Queues) o un Durable Object de escritura, no replicas. Las 6 conexiones importan: un turno con modelo + tool + Telegram ya son tres sockets; un fan-out de tools las agota.
Fly.io
fly scale count 2 arranca dos Machines. No montan el mismo volumen: Fly documenta mapeo 1:1 — un volumen se adjunta a una Machine, una Machine monta un volumen. scale count crea volúmenes nuevos y vacíos (o reusa desadjuntos) y no copia datos. El resultado de subir count con sqlite en disco no es “database is locked” por dos writers en un archivo: son dos discos distintos, dos bots, cerebro partido.
Volumen = una Machine de escritura. Escala lecturas en otro proceso, no el bot que escribe sqlite. Autostop de cold starts no sustituye este techo. HA de sqlite en Fly es LiteFS u otro motor con replicación, no scale count 2.
Railway
Vertical por defecto: el servicio crece hasta el vCPU/RAM del plan. Horizontal: réplicas a mano en settings. Cada réplica tiene el techo completo del plan (docs: Pro hasta 24 vCPU / 24 GB por réplica; dos réplicas → hasta 48/48 repartidos). Tráfico público se reparte al azar en la región; multi-región, al más cercano y luego al azar. No hay sticky sessions.
Métricas de N réplicas se suman (2 × 100 MB = 200 MB en el tab). Horizontal + sqlite en volumen es carrera de writers: Railway no promete un writer único ni sesión pegajosa. Vertical (más RAM/CPU) es más seguro para un agente con estado. Réplicas tienen sentido si cada una es un worker de cola sin el webhook de Telegram.
Compose
deploy.replicas en Swarm/Compose no magia el sqlite. Un servicio agent con replicas: 2 y un bind mount es un incidente. O una réplica, o Postgres/Redis compartido.
Tabla

| Plataforma | Palanca verificada | Estado local | Stateless |
|---|---|---|---|
| Vercel | Fluid + auto hasta 30k (Hobby/Pro); burst 1000/10s/región | no clones; semáforo de LLM | deja Fluid |
| Workers | isolate por request; 128 MB; 6 conexiones | 1 Durable Object de escritura | request isolation |
| Fly | scale count crea Machines; volumen 1:1, vacíos al escalar | count 1 + volumen | count N sin volumen compartido |
| Railway | vertical al techo del plan; réplicas a mano; sin sticky | vertical primero | réplicas si no hay sqlite local |
| Compose | deploy.replicas | 1 | N detrás de cola |
Errores comunes

| Síntoma | Causa | Fix |
|---|---|---|
| El bot contesta dos veces | dos procesos, un webhook | una réplica o lock |
| sqlite “database is locked” | dos procesos, un archivo | un writer |
dos sqlite vacíos tras scale count | Fly no replica volúmenes | count 1 o LiteFS |
| 429 del proveedor | N turnos × tools | semáforo / cola |
503 FUNCTION_THROTTLED | burst 1000/10s/región | cola, no más Functions |
| Worker 1102 / CPU | loop de tools en un request | menos tools o Paid + límite |
| Railway bill sube | réplicas idle | vertical, no N=5 |
Relación con el resto
- Primer hit lento: cold starts.
- Matar una réplica: graceful shutdown.
- Disco: backup.
- Deploy base: comparativa.
Checklist
- Sabes si el estado es local o externo
- Webhook de prod → un solo proceso
- Tope de llamadas al modelo en vuelo
- Fly: no asumas que
scale countcomparte el sqlite - Railway: sin sticky; no uses réplicas para sesión en RAM
- Workers: 6 conexiones / 128 MB no te sorprenden
- Ensayo: dos mensajes a la vez, una sola respuesta
FAQ
¿Réplicas para HA? HA de un sqlite es backup + restore, no dos writers. Postgres o LiteFS sí.
¿Vercel se “queda corto”? Casi nunca es réplicas. Es maxDuration, el semáforo o un 503 de burst.
¿Compose en una VPS? replicas: 1 hasta que el estado salga del disco.
El ensayo: manda dos updates de Telegram en el mismo segundo. Una respuesta. Si ves dos, ya tenías concurrencia accidental.
Siguiente paso: si una réplica basta y igual se cae, alertas y logs. Sin runtime: curso.
Lecturas relacionadas
Sigue explorando Deploy y otras piezas para builders.



