Как мы ускорили сборку в CI в три раза
Полгода назад сборка основного приложения в CI занимала девятнадцать минут. С этим можно было мириться, пока релизы выходили раз в неделю. Когда мы перешли на ежедневные выкладки, очередь из пайплайнов стала главным тормозом команды: разработчики переключались на другие задачи, теряли контекст и возвращались к ревью только на следующий день.
Сначала — измерить
Мы выгрузили длительность каждого шага за месяц и свели её в простую таблицу. Почти половину времени занимала установка зависимостей, ещё треть — тесты, которые шли последовательно, хотя друг от друга не зависят. Сама сборка, которую все считали виноватой, занимала меньше трёх минут.
Кэш зависимостей
Ключ кэша считаем по хешу lock-файла. Если lock-файл не менялся, зависимости поднимаются из кэша за сорок секунд вместо семи минут.
cache:
key:
files:
- package-lock.json
paths:
- .npm/
Кэшировать стоит каталог пакетного менеджера, а не готовый node_modules: установка остаётся воспроизводимой, а кэш не ломается при смене версии Node.
Параллельные шаги
Тесты разбили на четыре группы примерно равной длительности, разбиение пересчитываем раз в месяц по свежей статистике. Линтер и проверка типов теперь идут параллельно со сборкой, а не перед ней.
Что не сработало
- Общий кэш артефактов сборки между ветками давал больше ложных попаданий, чем пользы, и однажды выкатил в стейджинг вчерашний бандл.
- Более мощные раннеры ускорили сборку всего на пятнадцать процентов: узким местом были не процессоры, а сеть и диск.
Сейчас пайплайн проходит за шесть минут. Следующая цель — пять, и мы уже примерно понимаем, где их искать.