This document provides information on pipeline caching in Azure DevOps, discussing the Cache@2 Task, examples of caching NPM's shared directory and Cypress binary, caching with conditions, and addressing gotchas and FAQs related to caching.
Abstract
The context describes pipeline caching on Azure DevOps, explaining the Cache@2 Task and its input arguments - key, path, and restoreKeys. It provides examples of caching NPM's shared directory (Build) and Cypress binary (Test) and caching with conditions. The document also covers the Post-Job Cache task and highlights five gotchas related to cache not working, cache hit/restore not happening, using the correct path for defining relative paths, restricted scopes of caching, and slow caching on Windows build agents for cache sizes greater than a threshold. Additionally, the context provides a link to FAQs on pipeline caching.
Bullet points
Azure DevOps released pipeline caching feature in late 2019
Cache@2 Task has 3 input arguments: key, path, and restoreKeys (optional)
Examples of caching NPM's shared directory (Build) and Cypress binary (Test)
Caching with conditions using cacheHitVar task input
Post-Job Cache task added automatically to build pipelines
Gotcha #1: Cache not working if build fails
Gotcha #2: Cache hit/restore not happening if build steps change cache key value
Gotcha #3: Using correct path for defining relative paths on hosted build agent
Gotcha #4: Caching has restricted scopes at project, pipeline, and branch level
Gotcha #5: Slow caching on Windows build agents for cache sizes greater than a threshold
Exploring pipeline caching on Azure and it’s shortcomings
In late 2019, Azure DevOps finally released a feature to enable caching on pipelines. Pipeline caching on other platforms like AWS, Bitbucket is pretty straightforward and works like a charm.
Pipeline caching on Azure is slightly different and I’d say it’s still a work in progress. This means on some occasions it might not work as expected.
This article will explain how pipeline caching works on Azure DevOps and address the gotchas.
Cache@2 Task
This task has 3 input arguments -
key (required): unique key to identify the cache
path (required): path of the folder or file you want to cache
restoreKeys (optional): If key fails, this will be the fallback to find cache
Examples
1. Caching NPM’s shared directory (Build)
2. Caching Cypress binary (Test)
Cypress is a test framework whose binary goes into hundreds of megabytes (500–800 MB) and hence this below example shows how to cache it.
3. Caching with conditions
In most cases, you’d want to skip some steps if the cache is successfully restored (hit). For example, a step that installs dependencies can be skipped if the cache was restored. This is possible using the cacheHitVar task input.
Post-Job: Cache Task
Once you add caching to any build pipeline, Azure automatically adds a post-job cache task.
Don’t be surprised by this additional automated step. It takes care of uploading cache contents (the first time) & checks if the contents weren’t changed through the course of your build.
Gotcha #1
Cache not working? or not getting a cache hit?
Make sure your build is passing. If it fails, caching won’t work and post-job cache step “passes” however it doesn’t do anything (no logs is an indication).
Gotcha #2
Cache hit/restore still not happening? Check if you see this warning in the Post-Job Cache step.
##[warning]The given cache key has changed in its resolved value between restore and save steps;
If yes, then make sure none of your build steps between the Cache and Post-Job Cache step change the cache key value.
For instance, we use the below value as the cache key for our NPM example.
So let’s say there is a npm publish step in the build which changes the value of package-lock.json. In this case, you’ll never get a cache hit because package-lock.json (hash) is part of the unique cache key.
There are two workarounds — either remove the change causing step or remove package-lock.json from the key.
Gotcha #3
The documentation states to use ${Pipeline.Workspace} for defining relative paths on the hosted build agent.
However, not all folders on the hosted build agent are exposed via default variables. Therefore at times you might need to specify the absolute path like the above snippet — /home/vsts/.npm
Gotcha #4
Caching has restricted scopes at a project, pipeline and branch level.
Example: Let’s say you added caching for Pipeline A on develop branch. Now, if you create a new branch called feature/A and open a pull request against develop. The first pipeline run for this branch will have a “Cache miss” because it’s a new branch.
Thus caching is less useful when used with short-lived feature branches.
*This is mentioned in the docs but can be missed
Gotcha #5
On Windows build agents caching seems to be very slow for cache sizes greater than some threshold. This defeats the whole purpose of caching as you add caching to speed up builds and not the other way around.
So if you see builds taking longer than what it used to before caching, don’t worry you haven’t done anything wrong. It’s a bug which will be addressed soon.