Άρθρο 4 : Η παγίδα του cache της διαμόρφωσης Gradle
Publié le 26 September 2025
Εισαγωγή
Η περιπέτεια μας στη δημιουργία του plugin`site-baker`, Ακολουθήσαμε μια αυστηρή προσέγγιση TDD. Κάθε λειτουργία ήταν δοκιμασμένη, επικυρωμένη, και προεβαίναμε με εμπιστοσύνη. Και μίας μέρας, το απρόσμενο ήρθε. Οι builds άρχισαν να εμφανίζουν ανεπιθύμητη συμπεριφορά. Οι τροποποιήσεις στην λογική του plugin ή στα αρχεία ρύθμισης φανόταν να αγνοούνται, και οι λειτουργικοί δοκιμές μας, που προηγουμένως ήταν αξιόπιστες, απέτυχαν χωρίς εμφανή λόγο.
Αυτό το είδος προβλήματος μπορεί να είναι ανεκτό ερεθιστικό. Υπονομεύει την αξιοπιστία του εργαλείου και την εγκυρότητα του κώδικά μας. Μετά από μια έντονη περίοδο εντοπισμού σφαλμάτων, ο ένοχος εντοπίστηκε: οcache ρυθμίσεων του Gradle.
Το σύμπτωμα: φαντασματικές κατασκευές
Το πρόβλημα εμφανιζόταν με διάφορους τρόπους :
-
Έκανα τροποποίηση μιας συμβολοσειράς σε μια εργασία`println`, αλλά η παλαιά αλυσίδα συνεχιζε να εμφανίζεται κατά την εκτέλεση.
-
Αλλάζα μια τιμή στο αρχείο μου`managed-jbake-context.yml`, αλλά το πρόσθετο δούλευε ως αν το αρχείο δεν είχε τροποποιηθεί.
-
Οι λειτουργικοί τεστ, που δημιουργούν έργα τεστ σε πραγματικό χρόνο, απέτυχαν επειδή το πρόσθετο δεν φαινόταν να εντοπίζει τα αρχεία ρυθμίσεων που δημιουργήθηκαν πρόσφατα.
Όλα φαίνονταν όπως αν το Gradle εκτελούσε μια "version fantôme" του build μας, αγνοώντας τις τελευταίες αλλαγές μας.
Η έρευνα: Τι είναι ο cache ρυθμίσεων;
Η cache της ρύθμισης είναι μια σχετικά σύγχρονη και εξαιρετικά ισχυρή λειτουργία του Gradle, που είναι ενεργοποιημένη από προεπιλογή στις νέες εκδόσεις. Ο στόχος της είναι να κάνει τις κατασκευές ταχύτερες.
-
Κατά την πρώτη εκτέλεση, το Gradle εκτελεί τη φάση τουΔιαμόρφωση(ανάγνωση των`build.gradle.kts`, δημιουργία των εργασιών, λύση εξαρτήσεων) και κατασκευάει ένα γράφο εργασιών.
-
Στο τέλος αυτής της φάσης, GradleΣειριοποίησε αυτό το γράφημα εργασιώνκαι το αποθηκεύει σε cache.
-
Lors des επόμενες εκτελέσεις, αν τίποτα δεν έχει αλλάξει (scripts κατασκευής,
gradle.properties, etc.), GradleΠαράλειψη πλήρως τη φάση ρύθμισηςκαι χρησιμοποιεί το γράφημα εργασιών που είναι σε cache.
Ο κέρδος χρόνου είναι εντυπωσιακός στα μεγάλα έργα. Ωστόσο, αυτή η απόδοση κοστίζει: απαιτεί αυστηρούς κανόνες στον τρόπο που πρέπει να γραφούν τα πρόσθετα.
Η Αιτία του Προβλήματος : Ένα πλαγκιν μη συμμορφωμένο
Το πρόσθετο μας`site-baker`Παραβίαζε, αγνοώντας, πολλές κανόνες του cache της διαμόρφωσης. Για να είναι σειριοποιήσιμο ένα γράφημα εργασιών, οι εργασίες δεν πρέπει να περιέχουν αναφορές σε σύνθετα αντικείμενα όπως το αντικείμενο`Project`ή να διαβάζετε αρχεία τυχαία κατά τη φάση εκτέλεσης.
Το κύριο λάθος μας ήταν η ανάγνωση του περιεχομένου του αρχείου YAML مستقیم εντός της λογικής εκτέλεσης της εργασίας, χρησιμοποιώντας μια αναφορά στη διαδρομή που αποθηκεύεται στην επέκτασή μας. Αυτή η προσέγγιση είναι ασυμβίβαστη με το cache, επειδή το Gradle δεν μπορεί να ξέρει αν το περιεχόμενο του αρχείου έχει αλλάξει εάν αυτή η ανάγνωση δεν είναι μοντελοποιημένη ωςεισόδος εργασίας(Task Input).
Η Προσωρινή Λύση : Απενεργοποίηση του Cache
Για να ξεπερνούμε το μπλοκ και να αποκαταστήσουμε έναν προβλέψιμο συμπεριφορικό χαρακτήρα κατασκευής, η γρήγορη λύση ήταν να απενεργοποιήσουμε την cache ρυθμίσεων. Αρκεί να προσθέσουμε την ακόλουθη γραμμή στο αρχείο`gradle.properties`του έργου που χρησιμοποιεί το πρόσθετο (ή στην περίπτωσή μας, το δοκιμημένο έργο)site-baker).
# site-baker/gradle.properties
org.gradle.configuration-cache=false
Αμέσως, τα builds επανήλθαν στον κανονικό τρόπο λειτουργίας τους. Κάθε εκτέλεση επανεκκινούσε τη φάση διαμόρφωσης και οι αλλαγές μας ληφθήκαν υπόψη.
Ωστόσο, είναι μια προσωρινή λύση, όχι μια βιώσιμη λύση. Θυσιάζει την απόδοση και δεν λύνει το θεμελιώδες πρόβλημα του προσθέτου μας.
Η αληθινή λύση: Κάνετε το plugin symbατό
Για να είναι ένα πρόσθετο (plugin) ένα αληθινό πολίτη του σύγχρονου οικοσυστήματος Gradle, πρέπει να είναι συμβατό με το cache ρυθμίσεων. Isso σημαίνει ότι πρέπει να επανασκέψουμε τον τρόπο με τον οποίο τα δεδομένα ροής προς τις εργασίες μας.
Η κλειδιά είναι να τα χρησιμοποιείςAPIs του παρόχουτου Gradle. Αντί να περάσεις τιμές άμεσες (όπως ένα`String` ou un File) στις εργασίες μας, πρέπει να περάσουμε από`Property<T>`ή κάποια`Provider<T>`.
-
Δήλωση των καταχωρισμών εργασιών :Η εργασία που αναλύει το αρχείο YAML πρέπει να δηλώσει αυτό το αρχείο ως μια είσοδος. Χρησιμοποιείται για αυτό την επίσημη σημείωση.
@InputFile. -
Χρησιμοποιήστε το
Propertyκαι τοProvider:Η τιμή του`configFile`θα συνδεθεί με την ιδιοκτησία`configPath`της επέκτασης DSL μας. Ο Gradle είναι έτσι ικανός να παρακολουθεί την προέλευση του δεδομένου.
[source,kotlin] (No output, as there is no French text provided to translate) στο πρόσθετο tasks.register<MyTask>("myTask") { configFile.set(extension.configPath.flatMap { project.layout.projectDirectory.file(it) }) } ----