Стендап Сьогодні 📢 Канал в Telegram @stendap_sogodni

🤖🚫 AI-free content. This post is 100% written by a human, as is everything on my blog. Enjoy!

Пости з тегом #CI

21.11.2024

Розширена інформація після невдалого тесту в Go

Захотілося, щоб після невдалого інтеграційного тесту я бачив журнал сервісів з Docker Compose. Бо в мене на CI вже й так журнал друкується наприкінці збірки, але за тим загальним журналом складно знайти потрібне місце.

Перше питання стало — як взагалі в Go викликати код після тесту? Рішення в стандартній бібліотеці не знайшов, але ті тести виконуються пакетом testify/suite, а в нього є метод TearDownTest(), проміж інших. Тож тут проблем немає.

…Далі, як дізнатися, що тест був невдалий? Я очікував якогось аргументу в колбеці, але ні. Насправді той обʼєкт *testing.T, навколо якого обертаються тести, має метод t.Failed(). (Взагалі раджу його вивчити детальніше, бо там багато чого цікавого, наприклад, можливість отримати тимчасову директорію для одного тесту - t.TempDir().) А в testify/suite, до речі, через s.T() отримуємо той самий обʼєкт.

(PS: а ще в testify/suite знайшов suite.HandleStats - якщо його оголосити, то цей метод буде викликаний наприкінці всього пакету зі статистикою про час виконання та результати тестів.)

Окей, тепер, як отримати логи? Спробував через програмний клієнт Docker… надто низькорівневий, бо він повертає для логи конкретного контейнера, та ще й потоком. А мені потрібні зведені логи всіх контейнерів в проєкті. Тому просто викликаю консольну команду docker compose. Для того є зручний високорівневий тип exec.Cmd. Йому можна прямо сказати “спрямуй вивід команди в мій вивід” і все, готово.


12.03.2025

Здається, починаю не любити GitHub Actions

Є в AWS офіційна “дія” для GitHub Actions, щоб розгортувати сервіси. Це чудово. От тільки якщо розгортувати достатньо багато сервісів, вона почне відвалюватися з перебільшенням обмеження на кількість. Та ніякого шляху розвʼязку — ані через GA, ані через саму дію — немає.

При тому, розвʼязок дуже простий — збільшити кількість повторних спроб. AWS CLI та всілякі SDK вміють це робити. А дія — ні. Тікет про це висить вже майже два роки. Хтось зробив виправлення, але його дедалі ігнорують.

Можна було взяти форк з виправленням, або зробити свій. Натомість я обрав структурно простіший шлях: замінити виклик дії на виклики AWS CLI. Це трохи складніше, бо прямої заміни немає, треба робити два виклики - aws ecs register-task-definition та aws deploy create-deployment. Також треба передавати дані з одного в інший та будувати JSON - що можна зробити з jq.

Зате я отримав рішення, яке побудоване на більш надійних та прозорих компонентах. Очевидно, що AWS CLI використовується на багато порядків більше, ніж це дія GitHub Actions, тому й підтримка в нього краще.

А загальний тут висновок у тому, що треба добре подумати перед тим, як додавати до збірки спеціальні дії. Подумати, в першу чергу, про те, чи не можна замінити її звичайним скриптом. Хоч це і йде всупереч з усією пропозицією GitHub Actions - що весь процес можна зібрати з кубиків, без всякого бридкого коду.

Та й чесно, не дуже в них хороша система для створення тих спеціальних дій. Найгірше — їх потрібно писати на JavaScript, тобто видрати шматок шелскрипта не вийде. Плюс обовʼязково треба додавати до Git повністю зібраний код дії — це наче логічно, але ускладнює розробку.

Якби зараз з нуля переписував систему CI, то орієнтувався б якомога більше на шелскрипти та доступні їм засоби спрощення (як-от звичайнісінький виклик програм, без всякої спеціальної магії.)


04.04.2025

Прискорення тестів на CI

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

Неприємність тут в тому, що не вийде прискорити тести простим киданням грошей на більші машини. Вигода від того буде обмежена. (Хоча якщо тестам не вистачає, скажімо, памʼяті, то збільшення машини точно буде вартим.)

Виконувати тести в паралелі на одній машині мені ніколи не вдавалося навсправжки. Бо в тестів є залежності. Навіть на Go треба явно оголошувати всі тести, які ти погоджуєшся запускати паралельно. В теорії, залежності можна ізолювати, але на практиці ніколи до цього не доходить.

Що залишається? Запускати тести в декількох задачах, звісно. Тут теж з першого погляду наче просто. Але щоб дійсно отримати вигоду, треба ще й поділити тести порівну. В мене є на то утиліта split_tests - але вона гарно працює, тільки якщо ви вимірюєте тривалість тестів. Та зберігаєте між збірками — що є окремою турботою.

А ще, окрім тестів обовʼязково є підготовчі кроки, які можуть бути довше за самі тести, та ще над ними доведеться шаманити. Бо тут від збільшення кількості паралельних задач тільки витрати зростають.

Але зрештою, якщо налаштувати split_tests в режимі JUnit, то виходить дуже непогано! Рекомендую.


09.04.2025

4 способи пришвидшити збірку CI на 10 секунд

Перекласти перевірку контейнерів пізніше. От потрібна вам база. Ви її оголошуєте як контейнер, разом із перевіркою готовності. Виходить, збірка чекає 10 секунд, поки база запуститься. А можна було перевірку готовності відкласти на пізніше, а за ті 10 секунд зробити встановлення залежностей тощо.

Зменшити кеш. Ні, серйозно, якщо у вас 500 Мб зайвого кешу, то достатньо його прибрати та збірка стане швидшою. Де взяти 500 Мб зайвого кешу? Наприклад, в тимчасових артефактах гему grpc (про що можна окремо розповідати.)

Навпаки, додати кеш Ну от кешуєте ви пакети, які завантажив yarn. З них можна повністю відтворити node_modules. Але то буде довго! Швидше самі node_modules теж закешувати. Відновлення кешу не моментальне, але швидше за yarn install.

Не робити зайвих анотацій Ясно, перед тестами потрібно промігрувати базу. А після міграцій автоматично запускається анотація моделей. Зручно локально. Абсолютно зайве на CI. Вимикаємо анотації — та замість 21 секунди міграції проходять за 11.

Можна спитати — а кому ті 10 секунд важливі? Самі собою, згодний, нікому. Але якщо 6 разів по 10 секунд - то це вже хвилина. А коли це хвилина паралельної збірки в 10 потоків - то вже 10 хвилин оплачуваного часу. А також одна хвилина, яку ніякою кількістю потоків не пришвидшиш. Так що інколи варто й на 10 секунд пришвидшувати.