---
title: "Cómo escalan Gurwi y Clatri bajo carga real"
description: "Clatri usa 0.02 vCPU mientras su base de datos se acerca a 90 conexiones abiertas. La telemetría muestra por qué escalar réplicas bloqueará Postgres antes de que el cómputo se agote."
image: "https://gurwi.com/api/og-cover?u=https%3A%2F%2Fgurwi.com%2Fapi%2Ffiles%2Forgs%2F3c969c06-4ae4-45f8-8baf-2e37e331e120%2Fassets%2F7d75aba2-6163-4042-b287-aeea89fc21f1.webp"
---

# Cómo escalan Gurwi y Clatri bajo carga real

## La ruta exacta de una solicitud a través de Cloudflare, Railway y Supabase

Cuando Camilo envía un mensaje de chat en Clatri, su teléfono primero le pregunta al DNS dónde vive la API. [Cloudflare] responde con una de sus propias direcciones perimetrales, por lo que la solicitud llega a un centro de datos de Cloudflare cercano a él. Ese centro de datos termina el TLS, aplica sus reglas de proxy y reenvía la solicitud al único nombre de host público que Railway le dio al servicio.

[Cloudflare] nunca ve las réplicas. Conoce un solo origen, el dominio de Railway, y envía todo allí, ya sea que el servicio ejecute una copia o diez. Agregar una réplica en Railway no cambia nada en la configuración de Cloudflare, porque Cloudflare actúa como una capa de DNS y proxy en esta configuración y no hace balanceo de carga entre contenedores.

[Railway] elige la réplica. Su enrutador perimetral recibe la solicitud en el dominio del servicio y la entrega a una de las instancias saludables de la API. Esa instancia ejecuta el código de la aplicación y, cuando necesita datos, abre (o reutiliza) una conexión a [Supabase], donde Postgres ejecuta la consulta y devuelve las filas.

Cada salto tiene una falla diferente. Un problema de DNS o certificado ocurre en Cloudflare, un contenedor caído o lento ocurre en Railway, y una consulta lenta o un grupo de conexiones lleno ocurre en Supabase. Saber a qué salto pertenece un síntoma evita que una sesión de depuración se convierta en adivinanzas.

![Dominios de falla distintos entre capas](https://gurwi.com/api/files/orgs/3c969c06-4ae4-45f8-8baf-2e37e331e120/assets/3961affb-dd15-4c40-a9e3-cfc20a3195d9.webp)

Dominios de falla distintos entre capas

## Por qué existen dos réplicas de API: despliegues sin interrupciones frente a la demanda de cómputo bruto

El escalado se realiza en dos direcciones. El escalado vertical le da a una instancia más CPU y RAM, y el escalado horizontal ejecuta más instancias idénticas una al lado de la otra. Tanto Gurwi como Clatri ejecutan su API de forma horizontal con 2 réplicas en [Railway], y la telemetría muestra que la demanda de cómputo no motivó esa elección.

La API de Clatri promedia 0.02 vCPU de 32 disponibles en [Railway]. El tráfico pico de Gurwi es de 2 chats por minuto. Ninguna de las dos cifras se acerca a saturar un solo contenedor, por lo que una segunda réplica casi no aporta capacidad bruta.

- s
- Esquema del enrutador perimetral de Railway que envía solicitudes a dos réplicas de la API
- RAILWAY · ACTUALIZACIÓN CONTINUA
- Enrutador
- perimetral
- API v1
- API v2
- En servicio
- Iniciando
- Saludable
- Desalojando
- Detenido
- En espera
- Verificación de estado 120 s · desalojo 60 s
- Solicitudes en curso activas
- Desplegar v2
- Restablecer
- Desplegando…
- La v1 atiende el 100 % del tráfico
- Verificación de estado: la v2 se está calentando
- Tráfico desviado · desalojando la v1
- Despliegue completo · la v2 da servicio

El despliegue de la versión 2 inicia una nueva réplica, espera hasta 120 segundos para su verificación de estado y, a continuación, desasigna la anterior durante 60 segundos mientras terminan sus chats en streaming.

La segunda réplica da sus frutos durante los despliegues. Cuando se lanza una nueva versión, Railway inicia los nuevos contenedores y espera a que pasen la verificación de estado (healthcheck), un punto final HTTP que la aplicación responde una vez que está lista. El período de la verificación de estado es de 120 segundos, por lo que una nueva compilación que no pueda responder en ese tiempo nunca se pone en rotación y la versión anterior sigue prestando servicio.

Una vez que las nuevas réplicas están saludables, Railway les transfiere el tráfico y da a las antiguas 60 segundos de drenaje. Durante el drenaje, los contenedores antiguos dejan de recibir nuevas solicitudes y terminan las que ya están en curso, como una respuesta de chat que aún transmite tokens. Con dos réplicas, al menos una instancia saludable siempre responde mientras la otra es reemplazada o falla, lo que elimina la breve interrupción que causaría una sola réplica en cada despliegue.

![La transmisión de chat de Camilo sin interrupciones durante los despliegues](https://gurwi.com/api/files/orgs/3c969c06-4ae4-45f8-8baf-2e37e331e120/assets/68ec3482-a2f3-40b4-b85d-83bf14f82fda.webp)

La transmisión de chat de Camilo sin interrupciones durante los despliegues

| Configuración | Valor | Capa | Lo que protege |
| --- | --- | --- | --- |
| Réplicas por API | 2 | [Railway] | Disponibilidad durante despliegues y fallas |
| Tiempo de espera de verificación de estado | 120 s | [Railway] | Las compilaciones con errores nunca reciben tráfico |
| Drenaje | 60 s | [Railway] | Las solicitudes en curso terminan limpiamente |
| CPU promedio de Clatri | 0.02 vCPU de 32 | [Railway] | Muestra que el cómputo está lejos del límite |
| Chats pico de Gurwi | 2 por minuto | [Railway] | Muestra que la carga está lejos del límite |

## Arquitectura de trabajadores y concesiones distribuidas

Cada producto divide su backend en dos servicios. La API responde a solicitudes HTTP y el trabajador ejecuta tareas en segundo plano, como procesar un documento subido. Tanto en Gurwi como en Clatri, el trabajador es un servicio de Railway independiente con 1 réplica, por lo que una tarea pesada nunca compite con las solicitudes de chat por la memoria de la API o el bucle de eventos.

Una única réplica de trabajador evita un error clásico. Si dos trabajadores consultan la misma tabla de tareas al mismo tiempo, ambos pueden leer la misma fila pendiente y procesarla dos vezes, lo que significa doble facturación para las llamadas al modelo y fragmentos duplicados en el índice. Ejecutar un solo trabajador hace que esa condición de carrera sea imposible por diseño.

- trabajos
- Supabase · Postgres
- id
- pendiente
- en ejecución
- completado
- trabajador A
- trabajador B
- omitido
- arrendamiento renovado
- liberado
- estado
- arrendamiento
- SELECT … FOR UPDATE SKIP LOCKED
- fila bloqueada

El trabajador A bloquea la fila #402 con un contrato de arrendamiento de 30 segundos y lo renueva a mitad del proceso, mientras que el trabajador B omite la fila bloqueada.

Las concesiones (leases) protegen al sistema incluso cuando esa suposición se rompe, por ejemplo, durante un despliegue en el que el trabajador antiguo y el nuevo se solapan durante unos segundos. Una concesión es un reclamo con tiempo limitado escrito en la base de datos [Supabase]. El trabajador marca una tarea como tomada por él mismo hasta una marca de tiempo dada, y otros trabajadores omiten cualquier tarea cuya concesión no haya expirado. Postgres hace que el reclamo sea atómico con un bloqueo de fila, típicamente a través de `FOR UPDATE SKIP LOCKED`, para que dos trabajadores nunca puedan tomar la misma fila en el mismo instante.

Si el trabajador muere a mitad de la tarea, deja de renovar la concesión. Una vez que pasa la marca de tiempo, la tarea vuelve a poder reclamarse y el siguiente trabajador la toma. Por lo tanto, la base de datos actúa como el árbitro, y el recuento de trabajadores se convierte en una decisión de rendimiento en lugar de un riesgo de corrección.

## Procesamiento de documentos en Gurwi: ganancias de rendimiento por concurrencia

El trabajador de Gurwi solía procesar documentos uno por uno. El parámetro `RESOURCE*WORKER*CONCURRENCY` era 1, por lo que una segunda subida esperaba en la cola hasta que terminaba la primera. El valor ahora es 3, lo que permite que la única réplica de trabajador maneje tres documentos en paralelo.

Los registros de Supabase del 7 de octubre muestran 6 documentos que tardan unos 111 segundos cada uno [Supabase]. Con el procesamiento en serie, el sexto documento termina después de 6 × 111 = 666 segundos, un poco más de 11 minutos, aunque su propio procesamiento tomó menos de 2.

![Cuello de botella de lotes de documentos con concurrencia simple](https://gurwi.com/api/files/orgs/3c969c06-4ae4-45f8-8baf-2e37e331e120/assets/af4f2752-e3db-4786-812a-7b460d17c9f0.webp)

Cuello de botella de lotes de documentos con concurrencia simple

Con una concurrencia de 3, los seis documentos se ejecutan en dos oleadas. Los primeros tres terminan en unos 111 segundos y los siguientes tres en unos 222 segundos, por lo que el lote se completa en menos de 4 minutos. El rendimiento aumenta de aproximadamente 0.54 a 1.6 documentos por minuto.

- Tiempo total de finalización del lote
- s
- Promedio listo en
- Cronograma de ejecución de seis documentos
- Concurrencia (espacios de trabajador)
- Concurrencia
- Doc.
- Espacio

Arrastra el control deslizante: con tres espacios, seis documentos de 111 s terminan en dos oleadas en lugar de seis turnos.

| Métrica | Concurrencia 1 | Concurrencia 3 |
| --- | --- | --- |
| Finalización de lote | 666 s | 222 s |
| Tiempo promedio hasta que un documento está listo | 388.5 s | 166.5 s |
| Rendimiento | ~0.54 docs/min | ~1.6 docs/min |

El tiempo de espera promedio es lo que más le importa al usuario. Con el procesamiento en serie, los tiempos de finalización son 111, 222, 333, 444, 555 y 666 segundos, con un promedio de 388.5. Con tres espacios, tres documentos terminan en 111 y tres en 222, con un promedio de 166.5. Ese cálculo asume que cada documento sigue tardando 111 segundos cuando se ejecutan tres a la vez. Si comparten una API externa lenta o saturan la CPU del trabajador, el tiempo por documento aumenta, por lo que las duraciones del 7 de octubre deben compararse con las mediciones posteriores al cambio antes de tratar la ganancia como definitiva.

La concurrencia también multiplica el trabajo de la base de datos. Tres documentos en paralelo pueden mantener tres conexiones y escribir tres fragmentos por segundo en Supabase.

![Más trabajadores, más trabajos en paralelo y Supabase quedándose sin conexiones en silencio](https://gurwi.com/api/files/orgs/3c969c06-4ae4-45f8-8baf-2e37e331e120/assets/555d6762-c45d-4442-a135-de4d755df498.webp)

Más trabajadores, más trabajos en paralelo y Supabase quedándose sin conexiones en silencio

![La concurrencia multiplicando la demanda de conexiones a la base de datos](https://gurwi.com/api/files/orgs/3c969c06-4ae4-45f8-8baf-2e37e331e120/assets/6564d781-c79f-479c-a34e-1f874158ac9b.webp)

La concurrencia multiplicando la demanda de conexiones a la base de datos

## Identificación de cuellos de botella: carga de la base de datos de Clatri frente a las colas de ingesta de Gurwi

Clatri y Gurwi se esfuerzan en lugares diferentes, y la telemetría lo hace visible. Clatri tiene más conversaciones activas. Registró 4561 mensajes en 30 días y un pico de 6 usuarios activos en el mismo minuto. Gurwi alcanza un pico de 2 chats por minuto, y su presión provino de los documentos en espera en la cola de trabajadores.

Para Clatri, la API está inactiva y la base de datos no. [Railway] muestra 0,02 vCPU de 32 en promedio, mientras que [Supabase] muestra un 74 % de RAM utilizada y 53 de 90 conexiones abiertas en la capa de computación pequeña. Postgres usa RAM para su caché y para la memoria de trabajo de cada conexión, por lo que el aumento de la RAM y del recuento de conexiones tienden a moverse juntos.

La saturación del grupo de conexiones se ve diferente a la saturación de la CPU. Cuando las 90 conexiones se llenan, las nuevas consultas esperan un espacio libre o fallan con un error de "demasiadas conexiones", incluso si la CPU de la base de datos está tranquila. Agregar réplicas de API empeora esto, ya que cada réplica abre su propio grupo. Las soluciones están en Supabase, a través de un agrupador en modo de transacción, grupos más pequeños por réplica o una capa de computación más grande.

- Espacios de conexión de Postgres
- Conjunto inactivo
- Consulta activa
- Libre
- CPU
- FATAL: remaining connection slots are reserved for non-replication superuser connections

Para Gurwi, el síntoma fue la latencia para el usuario que sube un documento mientras otros ya están en la fila. Las solicitudes de chat funcionaban bien y la base de datos tenía margen. La solución fue el cambio de concurrencia de los trabajadores de la página anterior, que afectó a la cola, no a la API.

| Señal | Clatri | Gurwi |
| --- | --- | --- |
| CPU de la API [Railway] | 0,02 vCPU de 32 | Bajo, pico de 2 chats/min |
| RAM de la base de datos [Supabase] | 74 % en computación pequeña | No es la limitación |
| Conexiones [Supabase] | 53 de 90 | No es la limitación |
| Posible primer cuello de botella | Memoria y conexiones de Supabase | Cola de documentos en el trabajador |

## Guía de solución de problemas operativos: CLI de Railway y telemetría de Supabase

Cada capa tiene sus propios instrumentos y leer el equivocado hace perder el tiempo. La CLI de Railway muestra lo que hacen los contenedores, y el panel de Supabase muestra lo que hace Postgres. Un vistazo rápido a ambos suele ubicar el problema en menos de cinco minutos.

## Capa de Railway

Estos comandos se ejecutan desde una terminal vinculada al proyecto. `railway link` selecciona el proyecto y el entorno, `railway status` muestra qué servicio está activo, `railway logs` transmite la salida de ese servicio y `railway variables` enumera configuraciones como `RESOURCE*WORKER*CONCURRENCY`.

```
<code>railway link
railway status
railway logs
railway variables</code>
```

En el panel de Railway, la pestaña Métricas de cada servicio muestra la CPU, la memoria y la red por réplica, y la pestaña Despliegues muestra si falló una comprobación de estado. Ejecuta estos comandos contra la API cuando las solicitudes fallen y contra el trabajador cuando los trabajos se detengan.

## Capa de Supabase

En el panel de Supabase, la sección Informes muestra la memoria, la CPU y el recuento de conexiones de la base de datos, que es de donde provienen el 74 % de RAM y las 53 de 90 conexiones. Rendimiento de consultas enumera las declaraciones más lentas y frecuentes. Para una vista en vivo, una consulta en `pg*stat*activity` muestra cada conexión abierta y su estado.

```
<code>psql "$SUPABASE_DB_URL" -c "select state, count(*) from pg_stat_activity group by state;"</code>
```

Muchas conexiones en `idle` generalmente significan grupos de aplicaciones que retienen espacios que no usan. Muchas en `active` con largas duraciones apuntan a consultas lentas, que Rendimiento de consultas puede nombrar.

![Terminal CLI de guía operativa interactiva que simula railway status, railway logs y Supabase pg_stat_activity…](https://gurwi.com/api/files/orgs/3c969c06-4ae4-45f8-8baf-2e37e331e120/assets/bc77d185-8c38-4817-bc8a-77d20c4d3149.webp)

Terminal CLI de guía operativa interactiva que simula railway status, railway logs y Supabase pg*stat*activity…

| Pregunta | Herramienta | Capa |
| --- | --- | --- |
| ¿Se está cayendo el contenedor? | `railway logs`, pestaña Despliegues | [Railway] |
| ¿Está alta la CPU o la memoria en una réplica? | Pestaña Métricas | [Railway] |
| ¿Cuál es la concurrencia de los trabajadores? | `railway variables` | [Railway] |
| ¿Están las conexiones cerca del límite? | Informes, `pg*stat*activity` | [Supabase] |
| ¿Qué consulta es lenta? | Rendimiento de consultas | [Supabase] |

## Arquitectura de extremo a extremo y diagnóstico de incidentes

Imagina un martes por la tarde. Los usuarios de Clatri informan que algunos mensajes fallan con un error del servidor, y el problema comenzó poco después de que se enviara un correo electrónico de marketing. Cloudflare muestra patrones de tráfico normales y el certificado TLS es válido.

La primera comprobación va a [Railway]. Ambas réplicas de API están saludables, la CPU se mantiene muy por debajo de una vCPU y `railway logs` muestra errores que mencionan que la base de datos rechazó nuevas conexiones. Los contenedores están bien y reportan un problema un salto más adelante.

La segunda comprobación va a [Supabase]. Los informes muestran las conexiones fijadas en 90 de 90 y la RAM por encima de su habitual 74 %. `pg*stat*activity` revela decenas de conexiones inactivas retenidas por los grupos de la API. El diagnóstico es la saturación del grupo de conexiones en la base de datos, y la respuesta es enrutar la API a través del agrupador de transacciones, reducir el tamaño de los grupos por réplica o subir desde la computación pequeña. Agregar réplicas de Railway abriría más conexiones y profundizaría la interrupción.

Un incidente de Gurwi el mismo día se vería diferente. Los usuarios dicen que sus archivos PDF cargados permanecen en procesamiento durante muchos minutos mientras el chat funciona normalmente. Las métricas de la API están tranquilas, Supabase tiene margen y la tabla de trabajos muestra un número creciente de filas pendientes. La limitación es la cola de trabajadores, y las palancas son `RESOURCE*WORKER*CONCURRENCY` y el tiempo de procesamiento por documento.

En ambos productos, la arquitectura mantiene la misma forma. Cloudflare está frente al dominio, Railway enruta entre 2 réplicas de API y ejecuta 1 trabajador por producto, y Supabase contiene los datos, las concesiones y el límite de conexiones. La mayoría de los incidentes de hoy aparecerán en la base de datos para Clatri y en la cola para Gurwi, mucho antes de que la API necesite más computación.

![Topología de producción completa para Gurwi y Clatri](https://gurwi.com/api/files/orgs/3c969c06-4ae4-45f8-8baf-2e37e331e120/assets/8253ec74-ea67-4a5b-a4fc-2443b557a86a.webp)

Topología de producción completa para Gurwi y Clatri

- Restablecer vista
- Diagrama en 3D: usuario, Cloudflare, enrutador de Railway, dos réplicas de la API, trabajador y Supabase Postgres
- Dispositivo del usuario
- Cloudflare
- TLS
- Enrutador de Railway
- Réplica de API ×2
- Trabajador ×1
- Supabase Postgres
- Conexiones
- Solicitud
- Respuesta
- Rechazada

Rota el diagrama para seguir una solicitud desde Cloudflare, pasando por el enrutador de Railway hacia una réplica y de regreso. El límite real se encuentra en el cilindro de la derecha, donde Postgres ocupa 90 de 90 conexiones y rechaza las nuevas.

## Cuándo tienen sentido las réplicas de lectura de Supabase para Clatri y Gurwi

Una réplica de lectura en Supabase es una segunda instancia de Postgres con su propia computación, su propia copia de los datos y sus propios límites de conexión, tanto directos como a través del agrupador. Solo sirve para lecturas. Cada inserción, actualización y reclamación de concesión sigue yendo a la principal, por lo que el trabajador de Gurwi seguiría escribiendo fragmentos y renovando concesiones en la misma base de datos que usa hoy.

Supabase establece varias condiciones para agregar una. El proyecto necesita un plan Pro, Team o Enterprise, debe ejecutarse en AWS con Postgres 15 o posterior, y necesita al menos un complemento de computación Pequeña. La réplica hereda el tamaño de computación de la principal. Los proyectos por debajo de XL pueden tener hasta 2 réplicas, y los proyectos en XL o superior pueden tener hasta 5. Supabase factura la computación, el disco, las IOPS y el rendimiento de cada réplica por separado, por lo que cada réplica agrega una segunda línea a la factura.

## Por qué una réplica deja el problema de Clatri en su lugar

El límite de Clatri es la cantidad de conexiones que acepta la base de datos principal, los 90 espacios que se llenaron durante el incidente del martes. Una réplica no hace nada por esos espacios a menos que la aplicación realmente le envíe tráfico de lectura, e incluso en ese caso, la réplica tiene su propio límite de conexiones que los grupos de la API pueden agotar de la misma manera. Agregar una mientras los grupos siguen sobredimensionados le deja a Clatri dos instancias que administrar y pagar, y cada una puede quedarse sin conexiones. La solución para las conexiones sigue siendo la misma que antes: usar el agrupador en modo de transacción, grupos más pequeños por réplica o un nivel de cómputo más grande.

## El orden de las palancas

El primer paso es optimizar las consultas lentas y confirmar el costo con `EXPLAIN ANALYZE`, que ejecuta una consulta e informa en qué gasta Postgres su tiempo. Si las lecturas representan menos del 80 % de la carga de trabajo, un nivel de cómputo mayor ayuda más que una réplica. Si la carga de trabajo está muy orientada a la lectura y la base principal ya está cerca del límite superior del escalado vertical (16XL), las réplicas pasan a ser el siguiente paso.

Las réplicas pueden tener sentido antes por dos razones. Una es aislar el trabajo pesado, como la generación de informes o análisis, para que un informe largo nunca ralentice las consultas que atienden los chats en vivo. La otra es atender lecturas desde una región más cercana a los usuarios, lo que reduce la latencia.

## Cómo crecería cada producto

Si el tráfico de Clatri aumenta, el diseño natural envía lecturas pesadas, como el historial de mensajes y los informes, a una réplica y mantiene cada escritura en la principal, con el agrupador al frente de ambas. Gurwi seguiría un camino diferente. Su cola de tareas pendiente sigue siendo el primer lugar a observar, y las réplicas solo llegarían una vez que el volumen de lecturas justifique la instancia adicional.

- Clatri
- Gurwi
- Diagrama de arquitectura
- Usuarios activos
- Porcentaje de tráfico de lectura
- Tareas en paralelo del worker
- Réplicas de API en Railway
- Cómputo de Supabase
- Pequeño
- Mediano
- Grande
- XL
- Escritura
- Lectura
- Cola
- Mensajes por usuario, 10 min
- Documentos por usuario, 10 min
- Texto
- Imágenes
- Otros
- Documentos
- Como está hoy
- tareas
- docs
- Usuarios
- {0} activos
- Cloudflare
- {0} sol/min
- Railway
- enrutador
- API ×{0}
- {0} / 32 vCPU
- {0} sol/min cada una
- {0} × 22 = {1} conex.
- Worker
- {0} tareas en paralelo
- entran {0} {1}/min
- {0}/min como máximo
- en cola: {0}
- Supavisor
- Modo de transacción
- {0} tx/s
- Postgres
- principal, {0}
- conex. {0}/{1}
- RAM {0} %
- CPU {0} %
- Réplica de lectura
- solo lecturas
- Postgres principal
- Cola del worker
- Réplicas de API
- Lo primero en romperse: el Postgres principal, con {0} de {1} conexiones y {2} de ellas desde los pools de la API. Siguiente palanca: subir el cómputo de Supabase.
- Lo primero en romperse: el Postgres principal, con la CPU o la RAM al {0} %. Siguiente palanca: subir el cómputo de Supabase.
- Lo primero en romperse: la réplica de lectura, con {0} de {1} conexiones y un pool por cada réplica de API. Siguiente palanca: menos réplicas de API o un cómputo mayor.
- Lo primero en romperse: la cola del worker, con {0} {2}/min entrando y {1} resueltos. Siguiente palanca: más tareas en paralelo.
- Lo primero en romperse: las réplicas de API, al {0} % de su capacidad. Siguiente palanca: añadir una réplica, y vigilar el pool de conexiones que abre.
- Lo primero en romperse: Supavisor, al {0} % de su caudal. Siguiente palanca: subir el cómputo de Supabase.
- Lo más cerca de su límite: {0} al {1} %. Todavía no se ha roto nada.
- Todo tiene margen. Lo más cargado: {0} al {1} %.

Gira el selector de lectura para ver cómo las lecturas pesadas se desplazan hacia la réplica, mientras que las escrituras y las reclamaciones de concesión (leases) permanecen en la primaria, con el agrupador (pooler) frente a ambas.

| Señal observada | Palanca correcta |
| --- | --- |
| Conexiones agotadas mientras la CPU se mantiene tranquila | Agrupador en modo de transacción y grupos más pequeños |
| Alta memoria RAM y CPU con una carga de trabajo principalmente de escritura | Nivel de cómputo mayor |
| Lecturas superiores al 80 % del tráfico | Réplica de lectura |
| Necesidad de aislar informes o atender otra región | Réplica de lectura, antes de alcanzar el límite vertical |

- Señal observada
- Conexiones agotadas
- CPU en calma
- Agrupador de conexiones (pooler) + grupos más pequeños
- Alto consumo de RAM y CPU
- Mayormente escrituras
- Nivel de cómputo superior
- Lecturas por encima del 80%
- del tráfico
- Réplica de lectura
- Aislar los reportes
- o atender otra región
- Réplica de lectura antes de llegar al límite
- Agrupador
- Cómputo
- Réplica
- Siguiente

Sigue cada síntoma hasta dar con la palanca que realmente requiere.

## Preguntas frecuentes

### ¿Por qué Clatri y Gurwi usan dos réplicas de API si el consumo de CPU es muy bajo?

La segunda réplica no aporta capacidad de cómputo, sino disponibilidad durante los despliegues. Con dos réplicas siempre hay al menos una instancia sana respondiendo mientras la otra se reemplaza o cae, eliminando la interrupción que provocaría una sola réplica.

### ¿Qué pasa si una nueva compilación no responde a la verificación de estado en 120 segundos?

Railway solo enruta tráfico a las réplicas que superan la verificación de estado. Si la nueva compilación no se vuelve saludable dentro de esa ventana, el despliegue falla y las réplicas existentes siguen atendiendo a los usuarios.

### ¿Por qué el trabajador de Gurwi y Clatri se ejecuta con una sola réplica?

Una única réplica de trabajador evita que dos trabajadores lean la misma fila pendiente y la procesen dos veces, lo que causaría doble facturación por llamadas al modelo y fragmentos duplicados en el índice. Ejecutar un solo trabajador hace imposible esa condición de carrera por diseño.

### ¿Qué es una concesión (lease) en el sistema de trabajadores?

Una concesión es un reclamo con límite de tiempo escrito en Supabase. El trabajador marca un trabajo como tomado hasta una marca de tiempo y otros trabajadores omiten los trabajos cuya concesión no ha expirado; si el trabajador muere, el trabajo vuelve a estar disponible al vencer.

### ¿Cómo mejoró el procesamiento de documentos al subir RESOURCE_WORKER_CONCURRENCY de 1 a 3?

Con concurrencia 1, seis documentos de unos 111 segundos terminaban en 666 segundos. Con concurrencia 3 se ejecutan en dos oleadas y el lote se completa en menos de 4 minutos, subiendo el rendimiento de aproximadamente 0.54 a 1.6 documentos por minuto.

```json
{"@context":"https://schema.org","@type":"LearningResource","name":"Cómo escalan Gurwi y Clatri bajo carga real","headline":"Cómo escalan Gurwi y Clatri bajo carga real","description":"Clatri usa 0.02 vCPU mientras su base de datos se acerca a 90 conexiones abiertas. La telemetría muestra por qué escalar réplicas bloqueará Postgres antes de que el cómputo se agote.","url":"https://gurwi.com/class/1nmtFXca1eu?lang=es","inLanguage":"es","datePublished":"2026-10-09T02:49:12.110859+00:00","dateModified":"2026-10-10T00:20:05.440788+00:00","isAccessibleForFree":false,"author":{"@type":"Person","name":"Jonnier Martinez"},"provider":{"@type":"Organization","name":"Jonnier Martinez","url":"https://gurwi.com/"},"image":"https://gurwi.com/api/og-cover?u=https%3A%2F%2Fgurwi.com%2Fapi%2Ffiles%2Forgs%2F3c969c06-4ae4-45f8-8baf-2e37e331e120%2Fassets%2F7d75aba2-6163-4042-b287-aeea89fc21f1.webp","hasPart":{"@type":"WebPageElement","isAccessibleForFree":false,"cssSelector":".gw-paywall-gated"}}
{"@context":"https://schema.org","@type":"FAQPage","inLanguage":"es","mainEntity":[{"@type":"Question","name":"¿Por qué Clatri y Gurwi usan dos réplicas de API si el consumo de CPU es muy bajo?","acceptedAnswer":{"@type":"Answer","text":"La segunda réplica no aporta capacidad de cómputo, sino disponibilidad durante los despliegues. Con dos réplicas siempre hay al menos una instancia sana respondiendo mientras la otra se reemplaza o cae, eliminando la interrupción que provocaría una sola réplica."}},{"@type":"Question","name":"¿Qué pasa si una nueva compilación no responde a la verificación de estado en 120 segundos?","acceptedAnswer":{"@type":"Answer","text":"Railway solo enruta tráfico a las réplicas que superan la verificación de estado. Si la nueva compilación no se vuelve saludable dentro de esa ventana, el despliegue falla y las réplicas existentes siguen atendiendo a los usuarios."}},{"@type":"Question","name":"¿Por qué el trabajador de Gurwi y Clatri se ejecuta con una sola réplica?","acceptedAnswer":{"@type":"Answer","text":"Una única réplica de trabajador evita que dos trabajadores lean la misma fila pendiente y la procesen dos veces, lo que causaría doble facturación por llamadas al modelo y fragmentos duplicados en el índice. Ejecutar un solo trabajador hace imposible esa condición de carrera por diseño."}},{"@type":"Question","name":"¿Qué es una concesión (lease) en el sistema de trabajadores?","acceptedAnswer":{"@type":"Answer","text":"Una concesión es un reclamo con límite de tiempo escrito en Supabase. El trabajador marca un trabajo como tomado hasta una marca de tiempo y otros trabajadores omiten los trabajos cuya concesión no ha expirado; si el trabajador muere, el trabajo vuelve a estar disponible al vencer."}},{"@type":"Question","name":"¿Cómo mejoró el procesamiento de documentos al subir RESOURCE_WORKER_CONCURRENCY de 1 a 3?","acceptedAnswer":{"@type":"Answer","text":"Con concurrencia 1, seis documentos de unos 111 segundos terminaban en 666 segundos. Con concurrencia 3 se ejecutan en dos oleadas y el lote se completa en menos de 4 minutos, subiendo el rendimiento de aproximadamente 0.54 a 1.6 documentos por minuto."}}]}
```
