Caching

Caching let you cache some files for later reuse. Caching happens at the project level so every run for the same project has access to all the cache entries created by previous runs. Every cache entry is distinguished by a key.

There are two steps to manage caching save_cache and restore_cache

During save_cache if the key already exists no new cache entry will be added.

restore_cache accepts a list of cache keys (that can be dynamically generated using a template). It’ll iterate over this list in order and will use the first matching key. Cache key matching is by prefix. If there’re multiple prefix matches, the newest cache entry will be used. prefix matching helps create a lot of useful caching modes. See below.

Cache key template

The cache key can be generated based on some information available only at runtime (like a file checksum). To achieve this, the cache key in the save_cache and the keys list in the restore_cache steps can be provided as a go templateCaching - 图1

This template can use some provided functions to generate the cache key.

Available template functions

FunctionDescription
md5sumCalculates the md5sum of the provided file
sha256sumCalculates the sha256sum of the provided file
envreturns the value of the provided environment variable (empty if it doesn’t exists)
osreturns the os name
archreturns the machine architecture
dayreturns the current day, with leading zero (01 - 31)
monthreturns the current month, with leading zero (01 - 12)
yearreturns the current year (i.e 2019)
unixtimereturns unix seconds (seconds since 1 Jan 1970)

Examples

  1. save_cache:
  2. key: go-mod-cache-{{ md5sum go.mod }}
  3. contents:
  4. - source_dir: /go/pkg/mod/cache

This will generate a cache key based on the md5sum of the go.mod file and save all the contents of /go/pkg/mod/cache

Caching strategies for project dependencies

Cache could be used to avoid fetching all the project dependencies at every run. You don’t need to have an uptodate cache of dependencies but you can just rely on a partial caching so the package manager will just fetch the missing/updated dependencies. To optimize it you can also save multiple caches at different key with an increasing degree of precision and in the restore_cache step provide a list of keys from the most precise to the less one

For example:

  1. restore_cache:
  2. keys:
  3. - go-mod-cache-sum-{{ md5sum go.mod }}
  4. - go-mod-cache-date
  5. dest_dir: /go/pkg/mod/cache
  6. run: go build .
  7. save_cache:
  8. key: go-mod-cache-sum-{{ md5sum go.mod }}
  9. contents:
  10. - source_dir: /go/pkg/mod/cache
  11. save_cache:
  12. key: go-mod-cache-date-{{ year }}-{{ month }}-{{ day }}
  13. contents:
  14. - source_dir: /go/pkg/mod/cache

In this example, in the save_cache step we are creating two cache keys (for the same contents). The first one is the more specific since it’s based on the md5sum of the go.mod file, the other one is based on the current day (so only one cache entry per day will be created). To always create a new cache entry for every run you can use

In the restore_cache step we are trying to first fetch a cache based on the go.mod md5sum, if such key doesn’t exists we’ll try to get a key based on the current day, if also this doesn’t exists we’ll try the first cache for the current month. Since keys are matched by prefix the last cache key will match every key of the current month. If we have the following cache keys:

go-mod-cache-20190415 go-mod-cache-20190414 go-mod-cache-20190410

If the step is executed at 20190425, then the key template go-mod-cache-- will generate a key: go-mod-cache-201904 and it’ll match by prefix go-mod-cache-20190415