top of page

Прибрали: як ми нарешті правильно користуємося кешем GitHub 🧹

Фото автора: Marcel Dütscher
Marcel Dütscher
27 лип.
Читати 4 хв

У минулому технічному дописі ми виміряли, чого насправді коштує наш конвеєр збірки й перевірок, і з'ясували: це не гроші, а час очікування та сховище. Той допис закінчувався словами «прибирання заплановане, але ще не зроблене». Виявилося, що воно пішло швидше, ніж очікувалося: від сьогоднішнього полудня воно в головній гілці. Ось цифри.


Спершу результат. Використання кешу в нашому репозиторії скоротилося з 5,32 ГБ у 63 записах до 2,46 ГБ у 13. Аналіз безпеки C#, який раніше запускався на кожному pull request, тепер займає там 4 секунди замість 4½ хвилин, і при цьому перевіряє все, що потрапляє до вас. І обидва результати без жодної відкинутої перевірки, яка вас захищає.


Коротко: для чого потрібен кеш? Кожна збірка стартує на щойно створеній порожній машині. Щоб щоразу не починати з нуля, вона може зберігати проміжні результати: наступного разу вона завантажує їх, а не створює заново. На це дається 10 ГБ на репозиторій. Коли місце закінчується, GitHub витісняє те, чим найдовше не користувалися. І це була саме наша проблема: місце було зайняте, але не тим, чим треба.


Помилка 1: ключ без платформи. Під час збірки Unity створює величезну проміжну теку. Нею користуються чотири збірки (Windows, Linux, macOS, WebGL), і кожній потрібна власна. Збірка для Windows була єдиною, чий ключ кешу не мав позначки платформи. Тож він збігався з першим доступним записом, а це був запис WebGL: завантажилося 1,7 ГБ, які Unity цілком слушно визнав «не звідси» й імпортував усе заново. У журналі: 257 секунд імпорту замість 85. Тепер ключ — Library-Windows-, і примара зникла.


Помилка 2: його ніхто ніколи не зберігав. Прикріша знахідка. Усі чотири збірки сумлінно намагалися відновити проміжну теку, але жоден workflow жодного разу її не записував. Єдиний наявний запис узяли з інструмента, який запускають вручну. Тож найважливіший кеш проєкту підтримувався випадково. 🙈 Тепер його записують навмисно.


Рішення, що економить місце: враховується лише критичний шлях. Очевидним кроком було б кешувати всі чотири платформи. Погляд на таймінги справжнього випуску показує, чому це було б нісенітницею: усі чотири збірки стартують одночасно, Windows завершується за 11 хвилин, Linux і macOS за 13,7, а WebGL за 31,6. Поки працює WebGL, інші й так чекають. Тож скорочує очікування лише його кеш; інші три коштували б близько 4,5 ГБ із наших 10 ГБ і заощадили б рівно нуль хвилин. Тому кешуємо рівно один.


Помилка 3: решту з'їв Docker. Під час збірки образів нашого сервера в кеш раніше зберігався кожен проміжний шар: приблизно 3,27 ГБ у 24 записах, 64% усього бюджету, з оновленням при кожному push. Цей потік надійно витісняв єдиний Unity-кеш, що має значення. Тепер зберігається лише фінальна стадія, а кожен із наших чотирьох образів має власний простір імен: раніше вони ділили один і постійно витісняли одне одного. З 3,27 ГБ лишилося приблизно 150 МБ.


Аналіз безпеки: перевіряти там, де це важливо. CodeQL, інструмент GitHub для пошуку дір у безпеці, був нашим другим за величиною пожирачем часу: 230 хвилин за вісім днів, майже все припадало на частину для C#, яка для аналізу перебудовує весь проєкт, і то на кожному pull request. Тепер вона повністю запускається під час злиття в головну гілку та раз на тиждень, а pull request лишаються зі швидкими перевірками. Виміряно після змін: 4 секунди в pull request і незмінні добрі 4 хвилини в головній гілці. Тож кожен рядок, що справді до вас потрапляє, як і раніше перевіряється, просто не втричі.


Дрібниці, що складаються. Пакети .NET тепер кешуються, але лише на шляху, на якому людина чекає. Емулятор для чужих архітектур процесорів налаштовується, лише коли ми справді збираємо під таку. Команду очищення, якій на щойно запущеній машині нічого було робити, але яка коштувала до 1,4 хвилини на збірку, прибрали. А проміжні файли збірки випуску тепер очищаються через 7 днів замість 90: назбиралося 703 таких файли загальним обсягом 7,4 ГБ.


Чого ми навмисно не робили. Дві пропозиції з нашого власного аналізу ми відкинули після вимірювання, замість того щоб продавати їх як гарні рядки в журналі змін. Розділення тестів на два паралельні завдання виграло б рівно чотири секунди (одна частина триває 2:54, друга 4 секунди) і перейменувало б обов'язкову перевірку, через що кожен pull request назавжди завис би в «очікуванні». А пропуск великого тестового шлюзу перед випуском теж нічого б не заощадив, бо він давно завершується, поки WebGL ще збирається. Оптимізація, що нічого не виграє, але прибирає страховку, оптимізацією не є.


А потім із цього випала справжня помилка. Посеред цього прибирання кожен pull request раптом почав провалювати ліміт часу: один тест тривав 212 секунд при дозволених 120. Другий за повільністю в тому ж запуску: 10,5 секунди. Причиною був шлях обробки помилок у нашому сервері, який просто обривав зламаний HTTP-запит, а не закривав його чисто. У Linux система повертає такі з'єднання лише під час очищення, що відбувається раз на дві хвилини, і завершення роботи терпляче на це чекало. У Windows цього не було видно, тому помилка кусала лише на збірковому сервері. Тепер сервер у такому випадку відповідає чесним кодом помилки й сам закриває з'єднання: тест завершується за добрі 20 секунд, а справжні гравці, що натраплять на таку незручність, отримають зрозумілу помилку замість обірваного з'єднання. День прибирання CI, який знаходить помилку в продакшені, — гарний день. 🐛


Нічого з цього безпосередньо нічого для вас не змінює: ні нового блока, ні нової тварини. Це просто скорочує дорогу між «закінчили кодити» і «можна встановити». І підтверджує те саме речення, що й минулого разу: спершу виміряй, потім чіпай. 🚀

Останні пости

Дивитися всі
Чому нова версія називається 2026.7.19, а не 0.9.2 🗓️

Хто оновлюється сьогодні, перестрибує з версії 0.9.1 на 2026.7.19. Це схоже на помилку друку, але це навмисне рішення: ми змінили схему версіонування, від «семантичних» версій до версій за датою (рік.

 
 

Коментарі


Коментування цього посту більше не доступне. Зверніться до власника сайту, щоб дізнатися більше.
bottom of page