서론

대상 : Gradle 개발자 중에서 이미 '매직’하거나 예상치 못한 빌드 동작을 경험한 사람들

플러그인을 만드는 우리의 모험`site-baker`, 우리는 엄격한 TDD 접근 방식을 따랐습니다. 각 기능은 테스트되고, 검증되었으며, 우리는 확신을 가지고 진행했습니다. 그리고ある日, 예기치 못한 일이 발생했습니다. 빌드가 예측할 수 없이 동작하기 시작했습니다. 플러그인 로직이나 구성 파일의 수정이 무시되는 것처럼 보였고, 이전에 신뢰할 수 있었던 기능 테스트가 명백한 이유 없이 실패하기 시작했습니다.

이러한 종류의 문제는 믿을 수 없을 정도로 좌절스러울 수 있습니다. 이는 도구의 안정성과 우리의 코드의 유효성을 의심하게 만듭니다. 강도 높은 디버깅 세션 후, 범인이 밝혀졌습니다: 그Gradle 구성 캐시.

증상: 유령의 빌드

문제가 여러 가지 방식으로 나타났습니다 :

  1. 저는 한 작업에서 문자열을 수정하고 있었습니다.println, 하지만 이전 문자열이 실행 중에 계속 표시되었습니다.

  2. 저는 내 파일에서 값을 바꾸고 있었습니다.managed-jbake-context.yml, 하지만 플러그인은 파일이 수정된 것처럼 행동했습니다.

  3. 기능 테스트는 즉석에서 테스트 프로젝트를 만들지만, 플러그인이 새로 생성된 구성 파일을 감지하지 못하는 것 같아서 실패했습니다.

모든 것이 마치 Gradle가 우리 빌드의 '유령 버전’을 실행하는 것처럼 진행되고 있었고, 우리의 가장 최근 변경 사항을 무시하고 있었다.

조사: 구성 캐시는 무엇입니까?

구성 캐시는 비교적 최신이면서 매우 강력한 Gradle의 기능이며, 최신 버전에서는 기본적으로 활성화됩니다. 그 목적은 빌드를 더 빠르게 만드는 것입니다.

원칙은 간단합니다 :
  1. 첫 번째 실행 시, Gradle은 단계를 실행합니다.구성(읽기의`build.gradle.kts`, 작업 생성, 의존성 해결) 그리고 작업 그래프를 구성한다

  2. 이 단계가 끝날 때, Gradle이 작업 그래프 직렬화그리고 그것을 캐시에 저장합니다.

  3. 이후 실행 시, 아무것도 변경되지 않은 경우 (빌드 스크립트,gradle.properties, etc.), Gradle설정 단계를 완전히 건너뛴다그리고 캐시된 작업 그래프를 재사용합니다.

시간 절약이 큰 프로젝트에서 놀라울 정도입니다. 그러나 이 성능에는 대가가 따릅니다: 플러그인이 어떻게 작성되어야 하는지에 대해 엄격한 규칙을 적용합니다.

구성 캐시의 수명 주기
@startuml
start
:Première exécution;
:Phase de Configuration;
:Création du graphe de tâches;
:Mise en cache du graphe;
:Phase d'Exécution;
end

start
:Exécution suivante;
if (Cache valide ?) then (oui)
  :Restauration du graphe depuis le cache;
  note right
    La phase de configuration
    est sautée !
  end note
else (non)
  :Phase de Configuration;
  :Mise à jour du cache;
endif
:Phase d'Exécution;
stop
@enduml

문제의 원인: 비준수 플러그인

우리 플러그인`site-baker`그는 알지 못한 채 구성 캐시의 여러 규칙을 위반하고 있었다. 작업 그래프가 직렬화 가능하려면, 작업은 복합 객체와 같은 참조를 포함해서는 안 된다.`Project`또는 실행 단계에서 임의로 파일을 읽을 수 있습니다.

주요 오류는 확장 프로그램에 저장된 경로 참조를 사용하여 작업 실행 로직 내에서 YAML 파일의 내용을 직접 읽는 것이었습니다. 이 방식은 Gradle이 파일 내용이 변경되었는지 알 수 없도록 이 읽기를 모델링하지 않으면 캐시와 호환되지 않습니다.작업 항목(작업 입력).

임시 솔루션: 캐시 비활성화

우리의 막힘을 풀고 예측 가능한 빌드 동작을 되찾기 위해 가장 빠른 해결 방법은 구성 캐시를 비활성화하는 것이었습니다. 파일에 다음 줄을 추가하기만 하면 됩니다.gradle.properties`플러그인을 사용하는 프로젝트 (또는 우리 경우, 테스트 프로젝트)`site-baker).

# site-baker/gradle.properties
org.gradle.configuration-cache=false

즉시, 빌드가 정상적인 동작을 되찾았습니다. 각 실행이 구성 단계를 다시 실행했고, 우리의 변경 사항이 반영되었습니다.

그러나 이것은 임시방편이 아니라 지속 가능한 해결책이 아닙니다. 성능을 희생시키고 우리 플러그인의 근본적인 문제를 해결하지 못합니다.

진정한 해결책: 플러그인 호환성 확보

플러그인이 현대 Gradle 생태계의 좋은 시민이 되려면 구성 캐시와 호환되어야 합니다. 이는 우리 작업으로 데이터가 흐르는 방식을 재고해야 함을 의미합니다.

핵심은 그것을 사용하는제공자 APIGradle의. 직접적인 값을 전달하는 대신 (예를 들어`String` ou un File) 우리의 작업에 대해, 우리는 통과해야 합니다`Property<T>`또는 일부의`Provider<T>`.

다음은 리팩터링 계획입니다 :

  1. 작업 항목 선언 :YAML 파일을 파싱하는 작업은 이 파일을 입력으로 선언해야 합니다. 이를 위해 어노테이션을 사용합니다.@InputFile.

[source,kotlin] ---- @get:InputFile abstract val configFile: RegularFileProperty ----


관련 기사