Як річка, якій 2000 років, навчила мене стабілізувати наш найважчий тест — майже не витрачаючи часу

Опубліковано  · Ігор Ткаченко

Вечірня сцена, що поєднує давній китайський кабінет із сучасним столом розробника — радісний засновник і мультяшні сови OwlMeans у китайських халатах обслуговують модель річки з рибинячим ротом і світний куб Kubernetes; заголовок: IT RUNS ITSELF

У 256 році до нашої ери губернатор на ім’я Лі Бін зіткнувся з річкою, яка щовесни виходила з берегів і топила врожай. Очевидним рішенням була дамба. Він її не збудував.

Він розділив річку Мін кам’яною дамбою у формі рибинячого рота і дозволив розподілу самому робити роботу — більша частина потоку на поля у сухі місяці, надлишок скидається назад у повінь, мул іде разом із ним. Жодних шлюзів, жодного персоналу. Річка регулювала себе сама й досі зрошує рівнину Ченду — двадцять три століття потому.

Цього місяця я багато думав про Лі Біна. Мій найважчий тест мав хворобу річки: він виходив із берегів при кожному запуску.

Потік, який не можна підробити

OwlMeans — це AI-пайплайн розробки: описуєш продукт у вигляді сторіз користувача, а спеціалізовані AI-ролі перетворюють їх у повноцінний застосунок, який належить тобі. Щоб протестувати це end-to-end, ти не можеш використовувати моки — запускаєш реальне.

Тест реєструє користувача, вводить промпт, чекає на специфікацію, підтверджує її — і тоді починається найважча частина: для цього проєкту піднімається новий sandbox Kubernetes, агент розробляє першу сторі всередині нього, і тест чекає, поки сторі не буде завершена. Від десяти до сорока хвилин, всі можливі асинхронні операції між ними — і всі можливі причини для нестабільності. Залишковий стан, наполовину розгорнутий sandbox, агент, що завис, інтерфейс, який змінюється на очах. Наївна версія — це вісімдесятихвилинний таймаут і молитва.

Половина, яку я не писав

Перша частина трюку: більшість цього я не будував.

Браузерна частина працює на нашому власному харнесі, @owlmeans/test-ui — одній зі спільних бібліотек OwlMeans, на яких побудовано кожен проєкт тут. Він запускає браузер, входить через наші ключі-супервайзера замість реального Google-логіну і обгортає Playwright-сантехніку так, що мій тест читається як опис намірів.

Sandbox теж не потребував моєї участі. Ефемерний Kubernetes-слот — namespace, storage, deployment, мережева політика — провізіонується і підтримується живим іншою спільною бібліотекою, @owlmeans/kephemeral: вона спостерігає за podом і лікує його, якщо він впаде. Вона вже знала, як триматися.

Залишився один потік для приборкання: як залежати від потоку, який реально займає сорок хвилин, не наглядаючи за ним?

Рибинячий рот

Не можна використовувати короткий таймаут — агент реально може думати сорок хвилин, і це нормально. Також не можна чекати вісімдесят хвилин, щоб дізнатися, що він помер на третій. Фіксований таймер — це дамба: надто низький — затоплює, надто високий — марний.

Тому я перестав вимірювати час потоку і почав читати його пульс. Агент витрачає токени під час роботи — це не проксі прогресу, це і є прогрес. Тест спостерігає за балансом токенів. Кожні двадцять секунд: ще спадає? Якщо так — агент живий, чекай скільки потрібно. Якщо зупинилося на десять хвилин — агент завис, і тест падає прямо зараз, а не дивиться в стіну ще годину.

Ось і весь задум: власна поведінка потоку говорить мені, чи він здоровий, так само як течія говорить дамбі Лі Біна, скільки пропустити. Тридцять рядків коду перетворили мій найнестабільніший тест на найнадійніший.

Чистий аркуш на вхід, чистий аркуш на вихід

Ще один витік. Запуск, перерваний посеред роботи, залишає за собою цілий sandbox — deployment, storage, сертифікати, маршрути, namespace — і наступний запуск спотикається об це сміття й не хоче стартувати.

Виправлення нудне і тотальне: перед кожним запуском і після нього тест знищує кожен проєкт на одному багаторазовому профілі. Як би попередній запуск не закінчився — чистий вихід, краш, закритий ноутбук — наступний стартує з відомого, порожнього стану. Ніякого ручного прибирання, ніколи — чистий аркуш на кожен запуск є найкращим, що ти можеш зробити проти нестабільних тестів, і тут це безкоштовно.

Акведук

Хмарна піктограма Cloudflare у лівому верхньому куті з'єднується вниз через relay-сервер, кам'яну аркаду тунелю (зашифрований тунель WireGuard) і маленький будиночок — домашній сервер — до світного куба з гербом Kubernetes; сова OwlMeans спостерігає з кута

Залишилася одна проблема, яку більшість так і не вирішує чисто: кластер працює на сервері вдома — без публічного IP, за провайдером, який не приймає вхідний трафік. Щоб тестувати його звідусіль і поставити попереду Cloudflare, мені потрібно було винести потік із дому.

Це окремий маленький проєкт, flt-pf-tnl: дешева хмарна VM з одним зарезервованим статичним IP, що запускає WireGuard і Nginx-проксі. Шлях простий — Cloudflare → relay → зашифрований тунель → домашній сервер → sandbox Kubernetes. Дві команди його запускають — лише Terraform, Ansible і кілька shell-скриптів. Watchdog кожні шістдесят секунд перевіряє файрвол і виправляє дрейф; статичний IP виживає після знесень, тому публічна адреса ніколи не змінюється.

Налаштовано один раз. Тримається. Акведук: збудований раз, працює на гравітації.

Можна просто отримати це

Відступи. Нічого з цього не є екзотичним — самолікуючий sandbox, зворотний зв’язок, що читає власний пульс потоку, тунель, що виносить приватний кластер у світ. Кілька днів правильної структури навколо потоку, який з’їдав мої вечори. Ця структура і є продуктом — та сама обіцянка, яку OwlMeans дає кожному застосунку: типізований монорепо та інфраструктура навколо нього, твої назавжди.

Тому ось чесний пітч.

Якщо ти будуєш щось реальне — ти наштовхнешся на цю стіну: повільні потоки, зовнішні залежності, sandbox, який треба підняти і знести, тести, які проходять у понеділок і падають у вівторок. Можна робити те, що робив я: спалити тижні, дізнаючись, що довший таймаут ніколи не лікує нестабільний потік, що треба читати його пульс, що доступ до власного кластера вимагає акведука. Для мене це було варто; це моя робота.

Це не твоя робота.

Це частина OwlMeans Services: ми беремо цей харнес, sandbox і тунель, адаптуємо їх до твого стека і розгортаємо за кілька днів. Все належить тобі — код, інфраструктура, жодного вендор-локіну, підтримується будь-яким агентом для кодування.

Потік, що запускає себе сам, — так само як річка тече вже двадцять три століття. Пропусти місяць, який витратив я — можна просто отримати це.


OwlMeans будує повностекові TypeScript SaaS-застосунки з ваших сторіз — типізовані, готові до SSO, ваші для подальшого розвитку з будь-яким агентом. Дивіться, що він вміє →