A vibe-coded video bot couldn't handle a second user: how it grew into a service running on six VPS instances
A friend used AI to build UNIQ, a Telegram bot that turns one video into several copies for Reels, Shorts and TikTok. The prototype worked as long as there was only one user. A second user exposed locking problems, a full disk and jobs that disappeared when a worker crashed. The developers moved to PostgreSQL, a queue with job leases and S3. The service now runs on six VPS instances.
AI-processed from Habr AI; edited by Hamidun News
Vibe coding works beautifully when a project has one user, and that user is you. On Habr, a UNIQ developer described how a Telegram bot that a friend built with AI became a service they could confidently sell. The main lesson: writing code is quick, but you still have to decide for yourself what correct system behavior means.
The starting point, and where it broke
UNIQ takes a video and produces between one and ten versions for republication: FFmpeg adjusts framing, speed, color and audio settings. The prototype used Python and SQLite and ran on the author's Mac. Disk space was the first problem: each order simultaneously requires the source video, temporary files and finished copies, so the developers added a 150 MB upload limit, a disk-space budget and cleanup.
The real turning point came when a second user joined the test. While FFmpeg was processing someone else's video, the new user opened menus and submitted their own video, and everything ran into global locks and scattered state. The developers decided against rewriting it in Go: switching languages doesn't remove a global lock or add CPU cores. Instead, they separated network waits, database queries and encoding.
A queue that survives crashes
To distribute jobs across multiple servers, they chose PostgreSQL: a shared database, transactions and row locking with FOR UPDATE SKIP LOCKED. A worker receives a lease on a job. If that worker stalls, another takes over the order once the lease expires. To prevent the original worker from overwriting the result when it resumes, each assignment generates a new ownership token, which is checked on every state write.
The effects plan is saved in advance, and completed copies are recorded in a checkpoint so the second worker can resume where the first crashed. A repeated request with the same identifier returns the saved receipt instead of executing the operation again. The developers also acknowledge a limitation: if a file reaches Telegram before the delivery record is saved, the copy may arrive twice. Internal idempotency doesn't give an external API exactly-once semantics.
Coins were a separate challenge. They turned out to require a small accounting system: batches with their own expiration dates, reservations and a transaction history. When an order is canceled, unused coins return to their original batches with their original expiration dates; otherwise, cancellations become a subscription that never expires. An order locks in the rate when it is confirmed, while a unique external transaction ID prevents a repeated payment notification from crediting the balance twice.
The improvement users could actually notice came from rearranging the workflow rather than optimizing it: encoding was separated from delivery, and copies are sent one at a time. In a run on a local test setup, they arrived after 40, 70, 105, 136 and 171 seconds. That put the first copy in the user's hands 131 seconds before the order finished.
Load-test figures and their limits
After moving videos to S3 and adding PgBouncer, with up to 2000 client connections sharing 10 server connections, the developers began measuring bottlenecks. A burst of 1000 order confirmations took 5.9 seconds, while the cumulative wait for a single SQL lock reached roughly forty seconds. They replaced the global exclusive lock with per-user locks, cutting the burst to 3.2 seconds.
Increasing the application's connection pool from 8 to 16 while PgBouncer was capped at 10 didn't speed anything up; it simply moved the queue. Encoding 20 short 720×1280 videos on 5 CPUs plateaued at just 4–5 workers, at around 29 jobs per minute. Twelve processes consumed 3133 MiB of memory and ran more slowly than five.
The menu handled 10 000 initial requests without errors, but p95 latency was around 30 seconds. As the developers rightly point out, accepting a request and responding quickly to a person are two different things.
Lessons to take away
These figures were measured with short videos on a specific test setup. They cannot be extrapolated to long 1080p videos or user counts. The questions, however, apply universally. What blocks what? Where does state live? What happens if a worker dies halfway through an order? What happens when a payment event is repeated? AI writes code quickly, but you still have to formulate the answers and verify them with tests yourself—preferably before the second user arrives.
- Nov 8, 2026FLUX 3 Max on fal.ai: 15 seconds of 720p video with sound, no sign-up required
- Nov 8, 2026Karpathy built HackerTube with Claude over a weekend: 6454 videos from 43 million comments
- Nov 8, 2026World models train robots and self-driving cars in simulations, while humans collect their data
- Nov 8, 2026DIYgod releases Pinky: an open-source bridge that lets AI agents control iPhone and Android
Key Questions Answered
What are the key details on The starting point, and where it broke?
UNIQ takes a video and produces between one and ten versions for republication: FFmpeg adjusts framing, speed, color and audio settings. The prototype used Python and SQLite and ran on the author's Mac. Disk space was the first problem: each order simultaneously requires the source video, temporary files and finished copies, so the developers added a 150 MB upload limit, a disk-space budget and cleanup. The real turning point came when a second user joined the test.
What are the key details on A queue that survives crashes?
To distribute jobs across multiple servers, they chose PostgreSQL: a shared database, transactions and row locking with FOR UPDATE SKIP LOCKED. A worker receives a lease on a job. If that worker stalls, another takes over the order once the lease expires. To prevent the original worker from overwriting the result when it resumes, each assignment generates a new ownership token, which is checked on every state write.
What are the key details on Load-test figures and their limits?
After moving videos to S3 and adding PgBouncer, with up to 2000 client connections sharing 10 server connections, the developers began measuring bottlenecks. A burst of 1000 order confirmations took 5.9 seconds, while the cumulative wait for a single SQL lock reached roughly forty seconds. They replaced the global exclusive lock with per-user locks, cutting the burst to 3.2 seconds.
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.
The AI world, distilled — once a week
Seven stories that actually mattered, hand-picked. No noise, no reposts, no press releases.
Done! Check your inbox for a confirmation.