W ostatnim wpisie o Cache Task w Azure Pipelines zajęliśmy się podstawową konfiguracją. Jeżeli zastosowałeś tamte wskazówki, przyspieszyłeś swój pipeline. Możesz wykonać kolejny krok, by wygenerować jeszcze większe przyspieszenie.
Jak przeprowadzić tuning Cache Task w Azure Pipelines? Wprowadź zmienne do key
, pobieraj częściowy cache z restoreKeys
lub pomiń całkowicie pobieranie pakietów.
Jak tego dokonać? Sprawdź poniżej.
Różne systemy operacyjne
Pipeline może być uruchamiany na różnych obrazach w zależności od wartości parametru vmImage
. Poszczególne obrazy dostarczają różne wersje oprogramowania, ale przede wszystkim różnią się systemem operacyjnym. Z perspektywy Cache, jest to ważne. Niektóre biblioteki mają różne wersje dla różnych systemów.
Nie chcemy, aby podczas pracy na Linuksie pobierały nam się pakiety windowsowe i odwrotnie. Może tak się stać jeżeli oprzemy klucz cachowania tylko na package-lock.json
.
Jak się przed tym chronić? Dodaj parametr do klucza w Cache Task. Będzie to wyglądać następująco:
pool:
vmImage: 'windows-2019'
steps:
- task: Cache@2
inputs:
key: '"$(Agent.OS)" | src/frontend/package-lock.json'
path: 'src/frontend/node_modules'
- task: Npm@1
inputs:
command: 'install'
workingDir: 'src/frontend'
Dzięki dodaniu "$(Agent.OS)"
do właściwości key
masz pewność, że cache zostanie pobrany tylko, gdy system operacyjny, będzie taki sam jak oryginalny.
Częściowy cache
Pamiętasz, jak mówiłem, że cache zostanie zignorowany, jeżeli zmieni się klucz haszujący? Domyślnie jest to prawda, ale możemy to kontrolować.
Weźmy na tapet taki przykład. Rozwijasz aplikację wymagającą półtora gigabajta pakietów. Siedzą one w cache, więc Cię to nie boli. Do momentu, aż musisz dodać nowy pakiet lub aktualizujesz część bibliotek.
Z nową wersją pakietów aktualizujesz packege-lock.json
, więc klucz keszowania będzie inny. Z tego powodu wszystkie pakiety zostaną pobrane od nowa. Co widać na screenie:

A gdyby zrobić tak, że pobierzesz stary cache i uruchomisz npm install
, aby pobrać tylko nowe paczki? Jest to możliwe. Pomoże Ci w tym właściwość restoreKeys
, a jej użycie wygląda następująco:
pool:
vmImage: 'windows-2019'
steps:
- task: Cache@2
inputs:
key: 'npm | "$(Agent.OS)" | src/frontend/package-lock.json'
restoreKeys: |
npm | "$(Agent.OS)"
path: 'src/frontend/node_modules'
- task: Npm@1
inputs:
command: 'install'
workingDir: 'src/frontend'
O co w tym chodzi?
Do key
dodaliśmy stałą wartość npm
na początek. Jest ona potrzebna, aby Azure Pipelines potrafił dopasować konkretny cache, gdybyśmy miał więcej niż jeden Cache Task.
Dodatkowo dodaliśmy restoreKeys
. Jest to informacja dla Cache Task, aby używać Cache z poprzednich wywołań, jeżeli nie ma plików dla aktualnego hasha.
Możemy mieć następujące scenariusze:
- Jest cache dla key – Wtedy pobierasz go i wszystko jest świetnie.
- Nie ma cache dla key, ale istnieje cache z identycznym początkiem klucza, czyli
npm | "$(Agent.OS)"
– w takiej sytuacji pobierzesz stary cache. - Nie ma cache dla key i nie istnieje cache z identycznym początkiem – wtedy nic nie pobierasz.
Dzięki takiemu rozwiązaniu kolejny task, czyli npm install
nie będzie pobierał wszystkich pakietów, a tylko sprawdzi, czy czegoś mu nie brakuje. Następnie po zakończonym kroku stworzy nowy cache z nowym kluczem. Co zmniejsza czas wykonywania całego pipeline. Co widać na screenie:

Zlikwidować npm install
Dodaliśmy restoreKeys
. Dzięki temu Cache Task czasem pobiera cały cache, czasem część, a czasem nic nie pobiera. W sytuacji, gdy pobrany jest cały, możemy pominąć npm install
.
Zanim zaczniemy pomijać zadania musimy wiedzieć w jakimś statusie zakończył pracę Cache Task. Aby to zrobić, dodajemy właściwość cacheHitVar
, która przyjmie wynik taska. Wygląda to następująco:
- task: Cache@2
inputs:
key: 'npm | "$(Agent.OS)" | src/frontend/package-lock.json'
restoreKeys: |
npm | "$(Agent.OS)"
path: 'src/frontend/node_modules'
cacheHitVar: CACHE_RESTORED
Może ona mieć następujące wartości:
true
– gdy cache zostanie pobrany w całości, bo key się zgadzainexact
– gdy zostanie pobrany stary cache na podstawierestoreKeys
false
– gdy nie zostanie pobrany cache
Wiedząc to, możesz dodać condition
do taska pobierającego zależności, aby go pominąć, jeżeli CACHE_RESTORED
jest równe true
.
Jako że Azure Pipelines w condition nie działa na zasadzie pomijana, ale w drugą stronę. Określasz kiedy dany task ma się wykonać. Musisz podać warunek, jeżeli CACHE_RESTORED
jest różne od true
to wykonaj to zadanie.
Gotowy pipelie będzie wyglądać następująco:
pool:
vmImage: 'windows-2019'
steps:
- task: Cache@2
inputs:
key: 'npm | "$(Agent.OS)" | src/frontend/package-lock.json'
restoreKeys: |
npm | "$(Agent.OS)"
path: 'src/frontend/node_modules'
cacheHitVar: CACHE_RESTORED
- task: Npm@1
inputs:
command: 'install'
workingDir: 'src/frontend'
condition: ne(variables.CACHE_RESTORED, 'true')
Dzięki takiemu rozwiązaniu task z npm install
będzie pominięty w odpowiednich sytuacjach:

Teraz jest wypas
Z taką konfiguracją jest wypas, bo:
- Jesteśmy zabezpieczeni przed zmianą systemu operacyjnego. Pamiętaj, że możesz dodawać kolejne parametry dla Twojego pipeline, jeżeli pobrane pakiety mogą się różnić od innego czynnika.
- Nie pobieramy wszystkich pakietów od nowa, gdy część zostanie dodana lub zaktualizowana.
- Nie uruchamiany
npm install
, gdy nie ma takiej porzeby
W związku z tym oszczędzisz jeszcze więcej czasu.
A jak Ty używasz Cache Task? Ile czasu na nim oszczędzasz?
Napisz mi w komentarzu.