The Jerusalem PostNvidia opens probe after report of CEO Huang's relationship with alleged Chinese spyPunchFG targets December 3 Inauguration for northern rail projectsDaily MaverickLOCAL ELECTIONS 2026: DA goes on coalition offensive as battle for Nelson Mandela Bay beginsZDF heuteAktuelle Pressemitteilungen des ZDFVarietyOscar Predictions: Best Casting — ‘Being Heumann’ and ‘La Bola Negra’ Found the Year’s Boldest Discoveries. Will the Academy Reward Them?CBS NewsNvidia investigates CEO Jensen Huang over Chinese espionage concernsالشرقأميركا.. جمهوريون يتوعدون بعزل هيجسيث في أول اجتماع لـ"النواب" بعد الانتخاباتn-tvIn leer stehendem Haus: Vermisste 13-Jährigen tot gefunden, mutmaßlicher Entführer schwer verletztStraits Times SportLens' nightmare week worsens with late Marseille defeatNOSBoot met migranten zinkt voor kust Senegal: zeker 34 dodenSouth China Morning PostIsrael’s President Herzog gives Gadi Eisenkot the first chance to form the next governmentPremium TimesLagos police ask political parties to notify command ahead of 2027 rallies
The Daily Newsstand · Free, Always
Sunday, November 8, 2026

Вайбкодинг закончился, когда пришёл второй пользователь

Translate

Бот уже отвечает. А продукт где? История разработки сервиса с ИИ.

Друг принёс мне работающего Telegram-бота. Он сам много публикует короткие видео и хотел дать уже снятому ролику больше попыток залететь в просмотрах, не готовя каждую версию вручную.

Присылаешь свой ролик, выбираешь одну, пять или десять версий и получаешь файлы для повторной публикации в Reels, Shorts или TikTok. Не нужно открывать редактор и возиться с каждой копией.

Проект назвали UNIQ. Обработкой занимается FFmpeg: меняет параметры кадра, темпа, цвета, звука и добавляет выбранные эффекты. Telegram — просто удобный вход: отправил видео, забрал файлы.

Код есть, результат есть. В списке оставшихся дел значился сервер. Всё остальное пока скромно притворялось готовым.

Идею назвали «дать хорошему ролику второй шанс».

Хотелось арендовать сервер, прикрутить оплату и открыть продажи. Но вмешались обычные вещи: закончившийся диск, параллельные пользователи и процесс, который мог умереть посреди заказа.

Оказалось, после первого готового видео разработка только становится интересной.

Сейчас UNIQ работает на шести VPS. Через собственную панель управляем обработкой, базой, мониторингом и обновлениями. Самого героя можно посмотреть в Telegram: @uniqvideobot. Ниже — как мы дошли до состояния, в котором сервер уже можно арендовать, а не надеяться на него.

Друг принёс вайбкод. Вайбкод даже работал

Прототип друг собрал с помощью ИИ. Он не программист, но смог довести идею до результата, который можно показать. Это уже гораздо предметнее объяснений на салфетке: вот исходник, вот получившаяся копия, вот что хочется продавать.

Внутри оказались Python, FFmpeg и SQLite — база в одном локальном файле. Запустил у себя, отправил видео, получил копию. Для проверки идеи удобно.

Начали с подготовки к Ubuntu, больших файлов и выбора VPS. ИИ быстро писал обвязку, а мы проверяли её на настоящем Telegram. Очередной успешный запуск приятно сокращал мысленный список оставшихся дел. До первого сообщения об ошибке.

Для больших файлов подняли собственный Local Bot API. Сам бот пока жил на моём Mac. И вскоре прислал вполне взрослое сообщение:

На сервере недостаточно свободного места. Попробуй позже.

«Сервер» стоял передо мной на столе. Ответ пользователю уже был, результата — ещё нет.

У одного заказа одновременно существуют исходник, временные файлы и готовые копии. К загрузке до 150 МБ добавили дисковый бюджет и очистку. После этой ошибки следующий этап начинался со сценария: файл должен поместиться, пережить обработку и освободить место. ИИ быстро дописывал код. Нам оставалось определить, что считать успешным результатом.

Как мы двигались от обработки файла к управляемому сервису

Как мы двигались от обработки файла к управляемому сервису

Второй пользователь сначала появился в тесте. Пока FFmpeg обрабатывает чужой ролик, он открывает меню, меняет настройки и отправляет своё видео. Его действия не должны ждать окончания чужого заказа, а несколько нажатий одного человека — путаться местами.

Вот здесь второй пользователь и закончил наш вайбкодинг. Понадобилось разобраться, кто кого блокирует, где живёт состояние и что можно выполнять одновременно. Второй человек ещё ничего не купил, а требования к системе уже принёс.

Переписывать всё на Go не стали. Ждать одну и ту же блокировку можно и на Go. Зато потом можно говорить, что у нас всё на Go. Основную работу выполнял отдельный процесс FFmpeg. Смена языка не убрала бы общую блокировку и не добавила процессорных ядер. Вместо переписывания разделили сетевое ожидание, запросы к базе и кодирование.

Так дошли до очереди. А вместе с ней — до первой задачи, которую нельзя было закончить проверкой «файл получился».

У одного ролика оказалось слишком много состояний

В прототипе уже была SQLite: несколько процессов могут работать с ней, но пишут в один файл по очереди. Нам предстояло раздавать задания разным VPS и сохранять подтверждение заказа вместе с резервом монет одной транзакцией. Раздавать серверам общий файл по сети ради этого не хотелось.

Выбрали PostgreSQL: общая база, конкурентные транзакции и блокировки строк. Два обработчика не должны забирать один заказ, а повторное нажатие — резервировать деньги дважды. Эти правила ещё нужно написать и проверить: замена базы сама по себе их не гарантирует.

SQLite при этом не отправили на костёр: в панели он остался для собственного инвентаря. Мы поменяли модель доступа к данным, а не нашли плохое слово в названии базы. Разницу хорошо описывают авторы SQLite.

Дальше разобрали один заказ из пяти копий. Обработчик A (worker) забрал его, сохранил первую готовую копию и завис. В базе у задания остались фаза encode и состояние running. Пользователь ждёт, а система должна решить, можно ли продолжать на другой машине. В тестах обработчик принудительно завершали, чтобы этот вопрос не оставался философским.

Дали работе срок владения — lease. Пока A жив, он продлевает аренду. Срок истёк — заказ может забрать B. При выдаче используем FOR UPDATE SKIP LOCKED, чтобы пропускать занятые строки, истечение аренды проверяем отдельно.

Теперь неприятная часть: A очнулся и тоже принёс результат. Старательный сотрудник, только полномочия закончились. При получении задания B выдали новый токен владельца. Каждая запись состояния проверяет токен и срок аренды, поэтому проснувшийся A уже не может изменить заказ.

План эффектов сохраняем заранее, а готовые копии — в checkpoint, сохранённой точке продолжения. B находит первую копию и делает оставшиеся, не выбирая эффекты заново.

Наконец, B сообщил API о выполнении операции, но ответ потерялся. Он повторяет запрос с тем же идентификатором и получает сохранённый receipt — результат уже принятой операции. Аренда позволяет продолжить работу, токен проверяет полномочия, checkpoint указывает место продолжения, receipt защищает от повторного изменения.

Путь задания от загрузки до результата

Путь задания от загрузки до результата

После восстановления взялись за отмену. Просто выставить флаг оказалось недостаточно: нужно остановить кодирование, дождаться дочернего процесса и фоновых файловых операций, только потом закрывать задание и убирать папку. Иначе уборщик и загрузчик могут устроить небольшой корпоративный конфликт вокруг одного файла.

С Telegram осталась честная граница: файл мог уйти, а запись об успешной отправке — не успеть. При такой аварии последняя копия может повториться. Внутренняя идемпотентность не делает внешний API exactly-once.

Когда эти сценарии стали воспроизводимо проходить, очередь перестала быть просто таблицей со статусами. Теперь на неё можно было опереться при добавлении денег.

«Просто монетки» оказались маленькой бухгалтерией

Поначалу обработку предполагали бесплатной. Потом понадобились стартовые монеты, рефералы, ручные начисления и покупки. Каждое начисление хранится отдельной партией со своим сроком. Сроки стали частью пакета: у купленных монет свои, у бонусных — свои. Покупка может продлить действующие купленные остатки. Кошелёк должен помнить условия начисления, а не пересчитывать прошлое по сегодняшнему тарифу.

Звучит как поле balance и пара дат. Но стоит отменить оплачиваемый заказ, и возникают подробности. В какую партию вернуть монеты? Какой у них теперь срок? Если начать отсчёт заново, регулярная отмена превращается в абонемент в вечность.

Появились партии, резервы и история операций. Возьмём условный пример, не действующий прайс: у пользователя 50 монет, копия стоит 4. Он заказывает пять копий: 20 монет резервируются, свободными остаются 30.

Две копии отправлены, пользователь отменяет остальные. За готовые списываем 8 монет, неиспользованные 12 освобождаем из резерва. Итог — 42 доступные монеты и нулевой резерв. Срок возвращённых монет остаётся прежним. Отмена заказа не омолаживает кошелёк.

Если в резерв попали несколько партий, остатки возвращаются в свои партии с исходными сроками. Сам заказ сохраняет подтверждённый тариф: администратор может изменить цену для новых заказов, но не переписать уже принятое обязательство.

Проверяли повторы: два нажатия не создают два резерва, повтор входа не выдаёт приветственный подарок снова. Изменение подарка не переписывает старые начисления. Реферальные условия и суточные лимиты стали настройками.

Для старых кнопок стали сохранять расчёт: параметры, цену, версию тарифа, срок и токен подтверждения. Сообщение со вчерашнего дня не должно тихо согласовать другой заказ по новой цене.

А вот сам экран становился всё длиннее. Пришлось пройти путь обычного человека и сократить его: видео, понятный расчёт, подтверждение. Остальное — в «Подробнее». Убрали дублирующие переходы, добавили историю и повторное получение результата без нового списания.

Покупки продолжили ту же историю с повторами: уведомление о платеже пришло дважды, событие потерялось, продажи выключены после выставления счёта. Повторное платёжное событие означает, что платёжка переспросила. А не что клиент решил заплатить ещё раз от избытка чувств. Параметры заказа фиксируются, внешняя транзакция имеет уникальный ID, начисление сохраняется вместе с платежом. Пропущенные события восстанавливает сверка.

Добавили Telegram Stars, ЮKassa и GetPlatinum, возвраты и сверку. Интеграция, тест и реальная оплата учитываются отдельно. Реквизиты профилей зашифрованы, ключ хранится вне БД. Монеты, рубли, Stars и доход продавца считаются раздельно. Для цифровых услуг внутри Telegram действуют правила оплаты в Stars.

Посреди этой бухгалтерии обнаружилась куда более заметная для пользователя вещь: бот готовил пять копий, а потом отправлял все сразу. Первая копия уже была готова, но ждала остальных. Даже у видео появилась зависимость от работы коллектива.

Разделили кодирование и выдачу. Worker публикует копию и checkpoint, шлюз сразу её отправляет.

Готовые копии выходят по одной, пока остальные продолжают обрабатываться

Готовые копии выходят по одной, пока остальные продолжают обрабатываться

В настоящем Telegram-прогоне копии пришли примерно через 40, 70, 105, 136 и 171 секунду. Первый результат появился на 131 секунду раньше конца заказа. Вычислений меньше не стало, зато человек перестал ждать всё с пустыми руками.

Отмена учитывает отправленное и останавливает остаток. Это конкретный ролик на локальном стенде, не обещание скорости любого VPS. Но перестановка оказалась полезнее многих оптимизаций.

«Сервера мы обеспечим». А что нужно обеспечить в коде

Когда заговорили о дополнительных нодах, первым делом пришлось отвязать видео от локальной папки. Иначе worker на второй VPS мог бы очень быстро и асинхронно сообщить, что исходника на первой машине он не видит.

Видео вынесли в S3, в PostgreSQL оставили ключи, размеры, SHA-256 и состояния. Worker скачивает исходник в папку своей попытки и публикует результат. Добавили проверку целостности, атомарную публикацию и уборку после сбоев. Готовые видео проверяли ffprobe и полным декодированием FFmpeg.

Множество процессов не должно означать отдельное соединение PostgreSQL для каждого клиента. Поставили PgBouncer: на стенде до 2000 клиентских подключений разделяют максимум 10 серверных, без дополнительного резерва. Это два уровня пула, не 2000 одновременно выполняемых SQL-запросов.

Два уровня соединений: приложение, PgBouncer и PostgreSQL

Два уровня соединений: приложение, PgBouncer и PostgreSQL

Пул приложения переиспользует клиентов, PgBouncer — соединения с PostgreSQL, выдавая их на время транзакции. Сеть вынесли за SQL-транзакции: десять соединений не должны ждать Telegram.

Как не занимать базу ожиданием работы

Даже пустая очередь создаёт нагрузку, если все worker постоянно её проверяют. В Job API добавили long polling: HTTP-запрос ждёт работу, не удерживая SQL-соединение. Ожидающие одной фазы используют общую проверку готовности. Пробуждение лишь предлагает повторить обычный транзакционный захват задания — владельца оно не назначает.

Периодические проверки остаются страховкой. Со старым API работает обычный polling. Для продления lease и сохранения checkpoint выделен отдельный запас HTTP-потоков: ожидающие задания не должны мешать уже работающим.

Дальше измерили, что ограничивает пропускную способность.

Сначала дали приложению тестовую волну из 1000 подтверждений заказов и измерили время до завершения всей волны. Получили 5,9 секунды. При этом суммарное ожидание одного вида SQL-блокировки набралось примерно на сорок секунд.

Машину времени мы не написали. Несколько соединений одновременно стояли у одной двери: заказы и настройки разных пользователей брали общий исключительный lock. Вот вам параллельное приложение — все могут ждать одновременно 😂

Развели обычные действия по пользователям, сохранив общую защиту там, где она нужна. На том же стенде 1000 подтверждений завершились за 3,2 секунды вместо 5,9. Это время всей волны, не обработки видео. Дополнительные серверы до исправления только прислали бы к двери новых желающих.

Полный COUNT очереди при каждой загрузке заменили транзакционным учётом мест: откат освобождает место, завершение не освобождает его дважды. Убрали повторную запись регистрации на каждую кнопку. Индексы добавляли под конкретные запросы: ускорение чтения оплачивается работой при записи. Проверяли пути доступа, а не собирали коллекцию ускорителей.

Под нагрузкой ответ на кнопку успевал так застрять в очереди, что Telegram переставал его принимать. Для человека это выглядело проще: нажал, индикатор крутится, ничего не понятно.

Подтверждение получения нажатия на основные кнопки отправили до бизнес-проверок в БД. Оно значит «нажатие получили», а не «заказ оплачен». Деньги и резерв проверяются прежним порядком, результат появляется в карточке. Финансовая логика не получила волшебного разрешения доверять кнопке заранее.

Увеличили пул приложения с 8 до 16 соединений при прежнем пределе PgBouncer в 10. Подтверждения не ускорились, ожидание у пулера выросло: очередь просто переехала. Большое число в конфиге оказалось довольно слабым аргументом. Для другой нагрузки размер нужно выбирать заново.

Кодирование проверили отдельно: 20 роликов 720×1280, три секунды, 25 FPS, звук, одна копия. VM имела 5 доступных CPU. FFmpeg, PostgreSQL и S3 настоящие, выдача Telegram заменена локальным приёмником.

Обработчиков

Время волны

Заданий в минуту

Пик RAM

2

78,14 с

15,36

644 МиБ

4

45,22 с

26,54

1166 МиБ

5

41,20 с

29,13

1419 МиБ

6

42,43 с

28,28

1691 МиБ

8

41,26 с

29,08

2168 МиБ

12

44,51 с

26,96

3133 МиБ

После четырёх-пяти производительность вышла на плато. Двенадцать процессов съедали больше памяти и делали меньше работы, чем пять. Добавили работников — работа пошла медленнее. Корпоративный опыт удалось воспроизвести даже на FFmpeg. Эти цифры относятся к коротким роликам и пяти CPU: переносить их на длинные 1080p-видео или считать количеством пользователей нельзя.

Меню проверили отдельно: 10 000 первых обращений, настоящий код и база, но имитация Telegram. Волна завершилась примерно за 30 секунд, p95 готового экрана тоже около 30 секунд — столько или меньше ждали 95% запросов. Для повторных обращений волна заняла около 16 секунд. Ошибок не было, но полминуты ожидания впечатляют совсем не в нужную сторону. Успешно принять запросы и быстро ответить человеку — разные результаты. Это не 10 000 настоящих Telegram-сессий или одновременно кодируемых роликов.

Дополнительный FFmpeg меню не ускорял. Выделили единый приёмник Telegram-событий (ingress) и общую очередь (inbox) в PostgreSQL. Событие сохраняется, затем забирается одним из core. ACK на схеме относится к получению обновлений от Telegram: сначала сохраняем событие. Ранний ответ на кнопку не заменяет эту запись. Внутри пользователя порядок сохраняется, разные пользователи работают независимо.

Ingress и общая inbox распределяют события между процессами UI core. Core A и Core B на схеме могут работать на одной VPS.

Ingress и общая inbox распределяют события между процессами UI core. Core A и Core B на схеме могут работать на одной VPS.

Состояние форм стало общим: ввод на core A не исчезает при подтверждении на core B. HAProxy отдельно балансирует Job API и исключает неготовые экземпляры. Периодические задачи оставили одному scheduler с защитой владения, чтобы новые core не размножали сверку и уведомления.

Для операций, включённых в журнал шагов обработчика, сохраняем результаты. Если процесс умер после изменения заказа, повтор события использует записанный результат и состояние диалога. Идентификатор шага проверяется: несовместимое продолжение останавливается, вместо того чтобы использовать результат другой операции. Сам перенос кода на другую строку не меняет идентификатор. Внешняя отправка сообщения в журнал не входит и после аварии может повториться. Мы знаем, какую часть цепочки контролируем. Для денег такая граница полезнее красивого слова exactly-once без уточнений.

Распределение событий и порядок действий проверили. Сопоставимого нагрузочного замера после перехода на inbox здесь нет: прежние 30 секунд относятся к ранней версии. Обещать ускорение или быстрый ответ для 10 000 активных пользователей пока нельзя.

На этом этапе «добавить сервер» наконец стало понятной операцией. Осталось определить, куда именно его добавлять.

Где жить сервису и что нужно перевозить за границу

При выборе размещения появилась новая вводная: основной регион может не иметь прямого доступа к Telegram. Перевозить вслед за ним всю систему было необязательно — нужно отделить саму зависимость.

Local Bot API и файловый шлюз выделили в роли для доступного Telegram региона. Базу и FFmpeg оставили в основном контуре, связь организовали через собственный HTTPS Job API. Команды идут через API, большие файлы — через S3.

Разделение Telegram-контура, API, обработки видео и хранилища. Конкретные роли на VPS показаны ниже.

Разделение Telegram-контура, API, обработки видео и хранилища. Конкретные роли на VPS показаны ниже.

У ноды своя API-идентичность, backend проверяет роль, фазу и владение заданием. Методы «выполни любой SQL» или «поправь баланс» worker не получает. Обработчики и S3 размещаем рядом, чтобы сократить передачу файлов между регионами. Ролику нужна была новая версия, а не международная карьера с пересадками между дата-центрами.

Базу выделили в отдельную роль: замена рабочей лошадки не должна перевозить кошельки пользователей. Несколько ролей при этом могут начинать на одной VPS.

Вариантов становилось всё больше. В какой-то момент пришлось остановиться:

Нам не нужен космолёт, нам нужен стабильный, хороший, понятный продукт.

Отложили преждевременные оптимизации. Некоторое время сервис оставался на Mac, с ограничениями питания, интернета и FileVault. Теперь он на VPS, а Mac перестал быть незаменимым продакшен-сервером под видом ноутбука.

К переезду роли обрели понятные связи. Получилось шесть VPS: control — панель и мониторинг, core — API и меню, edge — Telegram, worker — FFmpeg, db-01 и db-02 — основной и резервный PostgreSQL. Большие файлы связывает S3.

Это не шесть одинаковых копий всего приложения. При нехватке кодирования добавляем обработку, а не переносим вместе с ней кошельки пользователей. И это ещё не обещание отказоустойчивости каждого звена: один edge и один worker остаются одним edge и одним worker, сколько бы красивых стрелок мы ни нарисовали.

Собственные HTTPS-маршруты тоже могут пропасть, поэтому оставили проверки связности и возможность замены edge. Архитектура не должна обещать иммунитет от любой будущей блокировки.

Одна кнопка, чтобы пойти пить чай

В начале достаточно помнить несколько команд. Потом появляется команда на каждую роль, проверку и обновление. Отдать это другу как интерфейс управления было бы занятным способом закончить нашу историю.

Панель строили вокруг его рабочего дня: подключить сервер, выкатить изменение, заметить проблему и восстановить работу. Открыл — понятно ли, работает сервис или пора вмешаться?

Подключение сервера прошли глазами оператора. Хостер даёт адрес и SSH-доступ, а не параметры нашей внутренней сети. Человек вводит знакомые данные и выбирает роль, остальное выясняет автоматика.

Следующее действие — обновить программу. В панели видны работающие компоненты, история и готовые версии, прогресс — общий и по серверам. Сто процентов теперь должны означать завершённые этапы, а не настроение анимации.

За одной кнопкой пришлось сохранить весь процесс: конкретный Git commit, проверки совместимости, подготовку релиза, прежний артефакт для отката, установку и readiness. «Принято» не означает «готово».

Установщик работает вне панели: её обновление или закрытая вкладка не останавливают выкатку. После возвращения виден тот же журнал. Версию берём из запущенного приложения, а не оптимистичного сообщения сборщика.

Совместимая выкатка core: прогрев и readiness перед переключением, проверка результата и возврат прежнего образа при ошибке.

Совместимая выкатка core: прогрев и readiness перед переключением, проверка результата и возврат прежнего образа при ошибке.

Лёгкое обновление на Mac осталось режимом разработки. На VPS панель собирает образ из Git, проверяет и передаёт узлам. Проверили совместимость соседних версий в обе стороны: старый worker с новым API и наоборот. Worker должен прочитать сохранённый план, продолжить выдачу и понять отмену.

Получили 13 зелёных тестов и проверили сами проверки: изолированно сломали поле ответа API, затем формат запроса клиента. Нужные сочетания версий перестали проходить.

Если после поломки контракта тест остаётся зелёным, это уже не тестирование. Это моральная поддержка. Контрактный прогон при этом не заменяет реальные транзакции и целую раскатку.

Откат программы не восстанавливает вчерашнюю финансовую базу поверх сегодняшних платежей. Чай должен остывать без уничтожения выручки.

Бесшовность начинается не с двух одинаковых контейнеров

Для совместимых обновлений core сделали два слота — blue и green. Пока одна версия обслуживает пользователей, вторая запускается рядом и проходит проверку готовности через /_info. Входной прокси и Telegram ingress остаются на месте. До успешной проверки трафик идёт старой версии.

На маленькой VPS нельзя удвоить всё приложение. Установщик проверяет запас RAM и прогревает одну новую реплику UI. Не хватает памяти — переключения нет, старая версия работает. Число реплик восстанавливается после завершения прежних. Получается blue-green с учётом счёта за сервер, а не только цвета прямоугольников на схеме.

Прокси Nginx проверяет конфигурацию и переключается без обрыва начатых запросов. Отдельно в БД меняется допуск обработчиков меню к inbox: старые процессы должны перестать брать новые события.

Старую версию убираем после проверки активных аренд и завершения прежних процессов прокси. Одного давнего сигнала, что процесс жив, недостаточно. Если занятость проверить не удалось, сохраняем её. Этап переключения, образ и конфигурация записаны на диск: оборвавшееся SSH-соединение не должно превращать откат в археологию.

Это путь обновления core. Edge и worker требуют завершения начатой работы и проверки готовности, панель может переподключиться. Полного отсутствия пауз при замене любого компонента мы не обещаем.

Одна база для старого и нового кода

Два слота бесполезны, если новая схема БД сломала старый код. У миграций есть окно совместимости: в базе записано, какой уровень кода разрешено запускать. При старте проверяются известные миграции и их контрольные суммы.

Панель проверяет совместимость работающих узлов. Совместимые миграции выполняются на db-узле до переключения приложений, при необходимости после резервной копии. PostgreSQL при этом не пересоздаётся. При управляемой репликации нужен отдельный план — обычная выкатка со сменой схемы блокируется. Для отката возвращаем прежние образы на совместимой базе, сохраняя сегодняшние платежи. Удаление колонок и другие ломающие изменения требуют отдельного плана или нескольких релизов.

Видеть результат, а не только зелёные контейнеры

Но успешная выкладка ещё не означает, что пользователь получил видео. Все контейнеры здоровы. Пользователь результата не получил. По версии контейнеров, день прошёл отлично.

Мониторинг связали с этапами: очередь, кодирование, передача, меню, БД и ошибки. RPS — число запросов в секунду. В него входит и служебный опрос, поэтому считать его пользователями нельзя.

Занят CPU и растёт очередь видео — нужна обработка. Растёт ожидание БД — разбираемся с запросами и блокировками. Ещё один кодировщик эту проблему не решит.

доступность, CPU, память и диск VPS

доступность, CPU, память и диск VPS

потребление CPU и RAM контейнерами, доля лимита памяти и время проверки связей между сервисами

потребление CPU и RAM контейнерами, доля лимита памяти и время проверки связей между сервисами

Начисления, тарифы, пакеты и отчёты тоже доступны в панели. Посмотреть заказ или помочь с балансом не должно означать «сейчас зайду в базу и что-нибудь поправлю».

Когда откатить код недостаточно

Оставался неприятный сценарий — потеря данных. Нужна резервная копия, которую умеем восстановить.

Зашифрованные копии PostgreSQL и настроек появились ещё на Mac. Историю Docker-образов дедуплицировали, копирование согласовали с очисткой. После переезда база и настройки панели остались разными объектами: восстановить инвентарь серверов — не значит восстановить оплаченные заказы.

Комплект должен быть самостоятельным, ключ — сохранён отдельно, восстановление проверяется вне рабочей финансовой базы. Копия на том же сервере не спасает от потери машины. Реплика не заменяет копию: она старательно повторяет не только полезные записи. С сертификатами проверили выпуск, продление и повтор неудачной установки.

На резервный PostgreSQL переключаемся управляемо: проверяем отставание и отключаем прежний основной узел. Второй сервер не означает автоматического выбора «кто громче ответил» или гарантии отсутствия потерь.

Иногда главная задача — остановить ИИ

Часть написанного в проект не попала. Например, попробовали общий ограничитель отправки в Telegram: при избытке запросов API отвечает 429 и просит подождать. У core уже были локальные паузы, мы хотели согласовать их между процессами. Дополнительный Python HTTP proxy дал 240–300 запросов в секунду против примерно 1000 напрямую. Ограничитель скорости действительно заработал. Первой ограничилась наша пропускная способность.

Вариант без проксирования проверили на имитаторе: 24 000 запросов без ошибок, но в одном режиме медиана RPS снизилась с 1142 до 1090. Массовые реальные 429 не подтвердились. Польза пока предполагается, расходы уже измерены — эксперимент убрали и не выкатывали. Готовый код не обязывает его внедрять.

С тестовыми окружениями остановились позже, чем следовало. Во время тяжёлых проверок Mac исчерпал ресурсы и перезагрузился. Мой отзыв был короче архитектурного документа:

Ты утилизировал всю память на ПК.

Для локальных тестов выделили лёгкую Linux VM с отдельным Docker daemon. Автоматика привязана к её сокету и узнаёт свои контейнеры и тома, не полагаясь на глобальный Docker context.

Пропавшая рабочая база не считается первым запуском. Нет нужных данных — автоматика останавливается, а не создаёт пустую базу. Главное, чтобы она не решила начать жизнь с чистого листа. У пользователей на этом листе были монеты.

Проверки разделили: контракты и интерфейс — без новых VM, база и S3 — в изолированных данных, сборка и приёмка Ubuntu — на подходящем сервере.

Приёмку автоматизировали через MTProto — программно управляемый Telegram-клиент. Подключили два настоящих аккаунта через QR: один проверяет админские сценарии, другой — границы прав пользователя и недоступность чужих заказов.

Проходили путь человека: файл больше 20 МБ, подтверждение, первая копия, отмена остатка, скачивание. Полученное видео полностью декодировали, монеты и резервы сверяли до и после. Настройки возвращали обратно.

Так обнаруживается разница между «метод отправки вызвался» и «пользователь получил исправный файл, а деньги учтены правильно». ИИ может быстро написать тест на первое. Для продукта нужна вся цепочка.

Проверки на телефоне и Desktop тоже оставили. Программный клиент умеет нажать кнопку, но не объяснит, почему на маленьком экране текст выглядит как инструкция к промышленному станку. После всех схем и транзакций мы снова возвращались к исходной задаче: человек отправил видео и должен удобно получить результат.

И у друга появились клиенты

После этой подготовки арендовали серверы и разложили систему по ролям. Панель получила реальные машины вместо локальной схемы.

Проверили связь компонентов и выкатку.

А у друга появились первые клиенты.

Вот работающий бот UNIQ. Снаружи всё должно оставаться простым: прислал видео, выбрал параметры, получил результат. Человеку не нужно знать про lease, PgBouncer и старого worker, который мог бы внезапно проснуться.

Не хватает обработки — добавляем рабочую ноду, сохраняя базу и кошельки на месте. Меняем код — обновляем и проверяем результат. При сбое есть состояние задания, журнал и метрики.

Первые клиенты ещё не означают, что проверены любые нагрузки и бизнес сошёлся. Зато проверять теперь можно реальный продукт.

Вайбкодинг я по-прежнему считаю полезным. Без него друг мог бы не принести работающую идею, а я потратил бы больше времени на реализацию.

Прототип и сервис разделяли транзакции, восстановление после сбоев, измерение задержек и защита денег. ИИ писал код и тесты, а решения требовали понимания системы. От части готовых оптимизаций отказались: польза не подтвердилась.

Код генерируется быстро. Непроверенные предположения накапливаются ещё быстрее. Пользователь потом обнаруживает их за вас — своим временем и своими деньгами.

Excel не делает человека финансовым аналитиком только потому, что умеет считать формулы. ИИ не делает человека инженером только потому, что умеет писать код. С его помощью можно учиться и делать всё больше, но отказаться от понимания системы при этом не получится.

Друг принёс прототип, который обрабатывал видео. Получился сервис, поведение которого можно объяснять, проверять и развивать.

Вот такую пользу ИИ я и хотел получить: быстро реализовывать осмысленные решения. А не быстро достигать момента, когда уже никто не понимает, почему всё опять сломалось.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.