IndustriaAnálisis · En radarHabr AI→ original

Un bot de vídeo creado con vibe coding no aguantó al segundo usuario: cómo acabó funcionando en seis VPS

Un amigo creó con IA UNIQ, un bot de Telegram que genera varias copias de un vídeo para Reels, Shorts y TikTok. El prototipo funcionaba mientras solo había un usuario. Con el segundo aparecieron los bloqueos, el disco lleno y las tareas que se perdían cuando fallaba un worker. Los desarrolladores migraron a PostgreSQL, una cola con concesiones temporales y S3. Ahora el servicio funciona en seis VPS.

Procesado por IA desde Habr AI; editado por Hamidun News
Un bot de vídeo creado con vibe coding no aguantó al segundo usuario: cómo acabó funcionando en seis VPS
Fuente: Habr AI. Collage: Hamidun News.
Escuchar artículo
Ficha técnica y cifras clave
ParámetroDatos
Fuente originalHabr AI ↗
Editor jefe
Dato clave #1Una concesión temporal de tarea con un token de propietario impide que un worker que vuelve a responder corrompa el pedido
Más workers no implican más velocidadcon 5 CPU, el rendimiento máximo se alcanzó con 4–5 procesos
Dato clave #3Sustituir el bloqueo global por bloqueos por usuario redujo el tiempo de una ráfaga de 5,9 a 3,2 segundos

El vibe coding funciona de maravilla mientras el proyecto tiene un solo usuario y ese usuario eres tú. Un desarrollador de UNIQ contó en Habr cómo un bot de Telegram creado por un amigo con ayuda de la IA se convirtió en un servicio que podían vender con confianza. La principal lección: escribir código es rápido, pero definir qué comportamiento del sistema se considera correcto sigue siendo responsabilidad tuya.

El punto de partida y dónde se rompió

UNIQ recibe un vídeo y genera entre una y diez versiones para volver a publicarlo: FFmpeg modifica los parámetros de encuadre, velocidad, color y sonido. El prototipo estaba escrito en Python, utilizaba SQLite y se ejecutaba en el Mac del autor. El primer problema fue el disco: cada pedido mantiene a la vez el original, los archivos temporales y las copias terminadas, así que añadieron un límite de subida de 150 MB, un presupuesto de espacio en disco y tareas de limpieza.

El verdadero punto de inflexión llegó cuando un segundo usuario se incorporó a las pruebas. Mientras FFmpeg procesaba el vídeo de otra persona, este usuario abría menús y enviaba su propio vídeo, y todo chocaba con los bloqueos globales y un estado disperso. Decidieron no reescribirlo en Go: cambiar de lenguaje no elimina un bloqueo global ni añade núcleos. En su lugar, separaron las esperas de red, las consultas a la base de datos y la codificación.

Una cola que sobrevive a los fallos

Para repartir tareas entre varios servidores eligieron PostgreSQL: una base de datos compartida, transacciones y bloqueos de filas mediante FOR UPDATE SKIP LOCKED. Cada worker recibe una concesión temporal sobre una tarea. Si se queda bloqueado, otro se hace cargo del pedido cuando vence la concesión. Para evitar que el primero sobrescriba el resultado al volver a responder, cada asignación genera un nuevo token de propietario, que se comprueba en cada escritura de estado.

El plan de efectos se guarda de antemano y las copias terminadas se registran en un checkpoint, de modo que el segundo worker continúa desde el punto del fallo. Una solicitud repetida con el mismo identificador devuelve el receipt guardado en lugar de ejecutar de nuevo la operación. También reconocen una limitación: si el archivo llega a Telegram pero no da tiempo a guardar el registro del envío, la copia puede llegar dos veces. La idempotencia interna no aporta semántica exactly-once a una API externa.

Las monedas plantearon otro reto. Resultaron requerir un pequeño sistema contable: lotes con sus propias fechas de caducidad, reservas e historial de operaciones. Al cancelar un pedido, las monedas no utilizadas vuelven a sus lotes originales con la misma caducidad; de lo contrario, cancelar se convierte en una suscripción que nunca vence. El pedido fija la tarifa en el momento de la confirmación, y un ID único de transacción externa impide que una notificación de pago repetida abone el saldo dos veces.

La mejora que percibió el usuario llegó al reorganizar el flujo, más que al optimizarlo: separaron la codificación de la entrega y las copias se envían de una en una. En una ejecución en un entorno de pruebas local, llegaron a los 40, 70, 105, 136 y 171 segundos. Es decir, la primera estuvo disponible 131 segundos antes de que terminara el pedido.

Las cifras de carga y sus límites

Tras trasladar los vídeos a S3 e incorporar PgBouncer, con hasta 2000 conexiones de cliente sobre 10 conexiones de servidor, empezaron a medir los cuellos de botella. Una ráfaga de 1000 confirmaciones de pedidos tardaba 5,9 segundos, mientras que la espera acumulada por un único bloqueo SQL llegaba a unos cuarenta segundos. Sustituyeron el bloqueo exclusivo global por bloqueos por usuario y redujeron la ráfaga a 3,2 segundos.

Ampliar el pool de la aplicación de 8 a 16 conexiones con un límite de 10 en PgBouncer no aceleró nada: la cola simplemente cambió de sitio. La codificación de 20 vídeos cortos de 720×1280 con 5 CPU alcanzó una meseta con apenas 4–5 workers: unas 29 tareas por minuto. Doce procesos consumían 3133 MiB de memoria y funcionaban más despacio que cinco.

El menú atendió 10 000 solicitudes iniciales sin errores, pero la latencia p95 rondó los 30 segundos. Los desarrolladores lo señalan con razón: aceptar una solicitud y responder rápido a una persona son cosas distintas.

Qué lecciones extraer

Las cifras se obtuvieron con vídeos cortos y en un entorno de pruebas concreto; no se pueden extrapolar a vídeos largos en 1080p ni a un número de usuarios. Las preguntas, en cambio, son universales. ¿Qué bloquea a qué? ¿Dónde reside el estado? ¿Qué ocurre si un worker muere a mitad de un pedido? ¿Qué pasa si se repite un evento de pago? La IA escribe código rápidamente, pero tendrás que formular las respuestas y verificarlas con pruebas por tu cuenta, preferiblemente antes de que llegue el segundo usuario.

Historia

Preguntas frecuentes sobre la noticia

¿Qué se sabe sobre El punto de partida y dónde se rompió?

UNIQ recibe un vídeo y genera entre una y diez versiones para volver a publicarlo: FFmpeg modifica los parámetros de encuadre, velocidad, color y sonido. El prototipo estaba escrito en Python, utilizaba SQLite y se ejecutaba en el Mac del autor. El primer problema fue el disco: cada pedido mantiene a la vez el original, los archivos temporales y las copias terminadas, así que añadieron un límite de subida de 150 MB, un presupuesto de espacio en disco y tareas de limpieza.

¿Qué se sabe sobre Una cola que sobrevive a los fallos?

Para repartir tareas entre varios servidores eligieron PostgreSQL: una base de datos compartida, transacciones y bloqueos de filas mediante FOR UPDATE SKIP LOCKED. Cada worker recibe una concesión temporal sobre una tarea. Si se queda bloqueado, otro se hace cargo del pedido cuando vence la concesión. Para evitar que el primero sobrescriba el resultado al volver a responder, cada asignación genera un nuevo token de propietario, que se comprueba en cada escritura de estado.

¿Qué se sabe sobre Las cifras de carga y sus límites?

Tras trasladar los vídeos a S3 e incorporar PgBouncer, con hasta 2000 conexiones de cliente sobre 10 conexiones de servidor, empezaron a medir los cuellos de botella. Una ráfaga de 1000 confirmaciones de pedidos tardaba 5,9 segundos, mientras que la espera acumulada por un único bloqueo SQL llegaba a unos cuarenta segundos. Sustituyeron el bloqueo exclusivo global por bloqueos por usuario y redujeron la ráfaga a 3,2 segundos.

ZK
Zhemal Khamidun — CPO de Alpina Digital, product manager de AlpinaGPT. Crea productos de IA desde 2019. Hamidun News es un proyecto personal que creció hasta ser un agregador en producción con más de 6.000 lectores.
✦ Unified AI Workspace · Nomad

Test Frontier LLMs & Autonomous Agents in One Workspace

Run Claude Opus 5.5, GPT-6, Gemini 3.1, and DeepSeek side-by-side in Nomad AI (nomadnet.ai) — unified model routing, deep research, and multimodal workflows under one subscription.

Try Nomad AI →Launch Nomad Agent
¿Qué te parece?
Cargando comentarios…