परिचय

लक्षित दर्शक: वे Gradle डेवलपर जो पहले से ही जादुई या अप्रत्याशित बिल्ड व्यवहार का सामना कर चुके हैं।

हमारी प्लगिन बनाने की यात्रा में`site-baker`, हमने एक कठोर TDD दृष्टिकोण अपनाया। हर फ़ंक्शनलिटी का परीक्षण किया गया, मान्यता प्राप्त की गई, और हम आत्मविश्वास के साथ आगे बढ़ रहे थे। और फिर, एक दिन, अप्रत्याशित स्थिति आई। बिल्ड्स अनियमित रूप से व्यवहार करने लगे। प्लगइन की तर्क में या कॉन्फ़िगरेशन फ़ाइलों में किए गए परिवर्तनों को अनदेखा किया जाना शुरू हो गया, और हमारे फंक्शनल टेस्ट, जो पहले विश्वसनीय थे, बिना किसी स्पष्ट कारण के विफल हो रहे थे।

इस प्रकार की समस्या अविश्वसनीय रूप से निराशाजनक हो सकती है। यह उपकरण की विश्वसनीयता और हमारे कोड की वैधता पर सवाल खड़ा करती है। एक तीव्र डिबगिंग सत्र के बाद, अपराधी पहचान लिया गया था: दग्रैडल कॉन्फ़िगरेशन कैश.

लक्षण : फैंटम बिल्ड्स

समस्या कई तरीकों से प्रकट हो रही थी :

  1. मैं एक कार्य में स्ट्रिंग को संशोधित कर रहा था।println, लेकिन पुरानी श्रृंखला चलते समय दिखाई देती रही।

  2. मैं अपनी फ़ाइल में एक मान बदल रहा था।managed-jbake-context.yml, लेकिन प्लगइन ऐसा व्यवहार कर रहा था जैसे फ़ाइल संशोधित नहीं की गई हो।

  3. फ़ंक्शनल टेस्ट्स, जो पर‑दे‑पैच पर परीक्षण प्रोजेक्ट बनाते हैं, असफल हो रहे थे क्योंकि प्लग़िन नए रूप से बनाई गई कॉन्फ़िगरेशन फ़ाइलों का पता नहीं लगा पा रहा था।

सब कुछ ऐसा लग रहा था जैसे Gradle हमारे बिल्ड का एक “फ़ैंटम संस्करण” चला रहा हो, हमारे सबसे हालिया बदलावों को अनदेखा करते हुए।

जाँच: कॉन्फ़िगरेशन कैश क्या है?

कॉन्फ़िगरेशन कैश एक अपेक्षाकृत आधुनिक और अत्यंत शक्तिशाली ग्रैडल सुविधा है, जो नए संस्करणों में डिफ़ॉल्ट रूप से सक्षम है। इसका उद्देश्य बिल्ड को तेज़ करना है।

साधारण सिद्धांत है:
  1. पहले निष्पादन के दौरान, Gradle चरण काकन्फ़िगरेशन(पढ़ने का)build.gradle.kts, कार्य बनाना, निर्भरताओं का समाधान) और एक कार्य ग्राफ़ बनाता है

  2. इस चरण के अंत में, Gradleइस टास्क ग्राफ़ को सीरियलाइज़ करेंऔर इसे कैश में रखता है।

  3. आगामी निष्पादनों के दौरान, यदि कुछ नहीं बदला है (बिल्ड स्क्रिप्ट्स,gradle.properties, etc.), Gradleयह पूरी तरह से कॉन्फ़िगरेशन चरण को छोड़ देता हैऔर कैश किए गए टास्क ग्राफ़ का पुनः उपयोग करें।

समय में बचत बड़े प्रोजेक्ट्स पर शानदार होती है। हालाँकि, इस प्रदर्शन की एक कीमत है: यह प्लगइन्स को लिखने के तरीके पर सख़्त नियम लागू करती है।

कॉन्फ़िगरेशन कैश का जीवन चक्र
@startuml
start
:पहला निष्पादन;
:कॉन्फ़िगरेशन चरण;
:कार्य ग्राफ़ का निर्माण;
:ग्राफ़ का कैश;
:निष्पादन चरण;
end

start
:अगला निष्पादन;
if (Cache valide ?) then (oui)
  :कैश से ग्राफ़ की बहाली;
  note right
कॉन्फ़िगरेशन चरण
छोड़ दिया गया !
  end note
else (non)
  :कॉन्फ़िगरेशन चरण;
  :कैश अपडेट;
endif
:निष्पादन चरण;
stop
@enduml

समस्या का कारण: गैर-अनुपालक प्लगइन

हमारा प्लगइन`site-baker`कन्फ़िगरेशन कैश के कई नियम अनजाने में उल्लंघन कर रहा था। एक कार्य ग्राफ़ को सीरियलाइज़ेबल होने के लिए, कार्यों में जटिल ऑब्जेक्ट्स जैसे ऑब्जेक्ट के संदर्भ नहीं होने चाहिए।`Project`या किसी भी फ़ाइल को निष्पादन के चरण के दौरान मनमाने तरीके से पढ़ें।

हमारी मुख्य त्रुटि थी कि हमने टास्क निष्पादन के भीतर YAML फ़ाइल की सामग्री को सीधे पढ़ा, अपने एक्सटेंशन में संग्रहीत पथ संदर्भ का उपयोग करके। यह दृष्टिकोण कैश के साथ असंगत है क्योंकि Gradle नहीं जान सकता कि फ़ाइल की सामग्री बदली गई है यदि इस पढ़ी को एक m…​ (truncated)कार्य प्रविष्टि(कार्य इनपुट)

अस्थायी समाधान : कैश को अक्षम करें

हम अनब्लॉक होने और पूर्वानुमेय बिल्ड व्यवहार को फिर से प्राप्त करने के लिए, सबसे तेज़ समाधान कॉन्फ़िगरेशन कैश को अक्षम करना रहा है। फ़ाइल में निम्नलिखित पंक्ति जोड़ना काफी है।gradle.properties`परियोजना जो प्लगइन का उपयोग करती है (या हमारे मामले में, परीक्षण परियोजना)`site-baker).

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

तत्काल, बिल्ड्स सामान्य व्यवहार में लौटीं। प्रत्येक निष्पादन ने कॉन्फ़िगरेशन चरण को फिर से आरंभ किया और हमारे परिवर्तनों को ध्यान में रखा गया।

हालाँकि, यह सिर्फ एक वैकल्पिक समाधान है, कोई स्थायी समाधान नहीं। यह प्रदर्शन की बलि चढ़ाता है और हमारे प्लगइन की मूल समस्या का समाधान नहीं करता।

सच्चा समाधान : प्लगइन को संगत बनाना

एक प्लगइन आधुनिक Gradle पारिस्थितिकी तंत्र में एक अच्छा नागरिक बनने के लिए, इसे कॉन्फ़िगरेशन कैश के साथ संगत होना चाहिए। इसका मतलब यह है कि हमें अपने कार्यों की ओर डेटा प्रवाह को फिर से सोचना होगा।

कुंजी यह है कि les का उपयोग करना हैप्रोवाइडर एपीआईGradle का. इसके बजाय मान पास करना (जैसे एक`String` ou un File) हमारे कार्यों को, हमें आगे बढ़ना होगा`Property<T>` ou des Provider<T>.

यह रिफैक्टरिंग की योजना है :

  1. कार्य प्रविष्टियों की घोषणा :YAML फ़ाइल को पार्स करने वाला कार्य इस फ़ाइल को एक इनपुट के रूप में घोषित करना चाहिए। इसके लिए हम एनोटेशन का उपयोग करते हैं।@InputFile.

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


संबंधित लेख