Загрузка
Все статьи

Gradle Kotlin DSL: кэширование и configuration avoidance — ускоряем сборку

Сборка Kotlin-проекта занимала 6 минут. После включения build cache, configuration cache и перехода на configuration avoidance API — 45 секунд. Рассказываю, что именно мы сделали, почему большинство туториалов по ускорению Gradle не работают, и как измерять реальный эффект от каждой оптимизации.

Шесть минут. Именно столько занимала сборка нашего монорепозитория с тремя Kotlin-модулями. Локально — 6 минут, в CI — 8 минут (холодный запуск). Разработчики тратили 20% рабочего времени просто ожидая сборку. Я решил это исправить и потратил две недели. Рассказываю по шагам, что дало реальный эффект, а что — нет.

Измеряем прежде чем оптимизировать

Первая ошибка, которую делают все — начинают включать флаги, не замерив текущее состояние. В Gradle есть встроенный profiler:

./gradlew assemble --profile --no-daemon

# Или подробнее:
./gradlew assemble --scan

--profile создаёт HTML-отчёт в build/reports/profile/. Там видно разбивку по фазам: Configuration, Execution, Up-to-date checking. В нашем случае: Configuration phase: 45 секунд. Execution phase: 4 минуты 30 секунд. Total: 5 минут 15 секунд. 45 секунд на конфигурацию для трёх модулей — очень много.

Build Cache

Build Cache в Gradle — механизм, который кэширует результаты тасок на основе хешей входных файлов. Если входы не изменились — таска не выполняется, результат берётся из кэша:

// gradle.properties
org.gradle.caching=true

Build Cache работает только для тасок, которые его поддерживают. Большинство стандартных тасок поддерживают, но кастомная таска требует явного указания входов и выходов:

abstract class GenerateOpenApi : DefaultTask() {
    @get:InputFile
    @get:PathSensitive(PathSensitivity.NONE)
    abstract val specFile: RegularFileProperty

    @get:OutputFile
    abstract val outputDir: DirectoryProperty

    @TaskAction
    fun generate() {
        // генерация OpenAPI спецификации
    }
}

После включения Build Cache наша сборка при неизменённом коде упала с 5:15 до 1:20. Почти 4 минуты сэкономили. Но холодная сборка в CI всё ещё занимала 5+ минут.

Configuration Cache

Configuration Cache кэширует результат фазы конфигурации — все build.gradle.kts файлы парсятся один раз, затем результат кэшируется. При следующих запусках фаза конфигурации пропускается целиком.

// gradle.properties
org.gradle.configuration-cache=true

Звучит просто, но половина плагинов сломалась. Kotlin Spring Plugin, Jooq Plugin — использовали API, несовместимый с Configuration Cache. Пришлось фиксить. Самая частая проблема — обращение к project в не lazy-контексте:

// БЫЛО (не работает с Configuration Cache):
tasks.test {
    val testDbUrl = project.property("test.db.url") as String
    environment("DB_URL", testDbUrl)
}

// СТАЛО (работает):
tasks.test {
    val testDbUrl = providers.gradleProperty("test.db.url")
    environment("DB_URL", testDbUrl)
}

После фикса конфигурация упала с 45 секунд до 3 секунд. 93% экономии.

Configuration Avoidance API

Не конфигурировать таски, которые не будут выполняться. Если запускаете ./gradlew test, зачем конфигурировать jar и dockerBuild?

// СТАЛО (lazy configuration):
tasks.registering(DockerBuildTask::class) {
    inputDir.set(layout.buildDirectory.dir("libs"))
}

tasks.named("test") {
    useJUnitPlatform()
}

Configuration Avoidance дал ещё 5 секунд экономии. Мало, но в совокупности — важно.

Итоговые результаты

Холодная сборка: 5:15 до 3:40 (Build Cache в CI шарится между раннерами). Горячая сборка (без изменений): 5:15 до 0:45. Ускорение в 7 раз. Build Cache дал 75% экономии execution phase, Configuration Cache — 93% экономии configuration phase. Главный совет: не верьте туториалам — измеряйте. Build Cache без правильно объявленных входов/выходов кастомных тасок не работает. Тратите время на профилирование, это окупается.

Поделиться статьёй

Комментарии

0
0 / 2000

Пока нет комментариев

Будьте первым, кто оставит комментарий к этой статье

Читайте также

Docker Compose для локальной разработки Kotlin-микросервисов — от 10 минут до 30 секунд старта

Как мы оптимизировали локальное окружение из 10+ микросервисов с помощью Docker Compose, multi-stage Dockerfile и правильных health checks.

15 июня 2026 10 мин

Terraform vs Pulumi — Infrastructure as Code для Kotlin-команды

Сравниваем Terraform на HCL и Pulumi на Kotlin для управления Kubernetes-инфраструктурой — с реальными примерами кода, болью миграции и нашим итоговым выбором.

14 июня 2026 11 мин

Nginx + PHP-FPM: тюнинг под высокую нагрузку — от 500 RPS до 5000 RPS

Сайт на PHP + Nginx выдерживал 500 RPS, а при 1000 начинал отдавать 502. Проблема была не в PHP-коде (он был оптимизирован), а в конфигурации Nginx и PHP-FPM: неправильный worker_connections, отсутствие keepalive к upstream, слишком маленький pm.max_children. Рассказываю пошагово, как мы увеличили пропускную способность в 10 раз.

23 мая 2026 11 мин