Skip to main content

Cached targets

A way to make your development cycle faster with Blaze is to use its built-in cache features.

This article explains how you can easily setup and fine tune cache for any target in your workspace.

Activate cache on a target​

Cache is disabled by default for all targets.

You can enable cache by adding a cache key to your target configuration :

project.json
{
"targets": {
"build": {
"executor": "std:exec",
"options": {
"program": "build.sh"
},
// an empty object means cache is simply enabled (without any further configuration)
"cache": {}
}
}
}

When cache is enabled on a target, it will not be executed again if it was already executed successfully with the same configuration, unless :

  • The options passed to the executor have changed.
  • The target configuration itself has changed.
  • The resolved executor is different than the one previously used.
  • The project's root directory has changed.
  • Cache invalidation is propagated from a dependency.

We can use cache invalidation strategies so that Blaze knows exactly how cache should be invalidated apart from these rules.

Cache invalidation strategies​

You can configure cache invalidation strategies using the invalidationWhen key :

{
"targets": {
"build": {
"executor": "std:exec",
"options": {
"program": "build.sh"
},
"cache": {
"invalidateWhen": {
// where we declare how to invalidate the cache ...
}
}
}
}
}

The supported implementations are listed in this documentation.

Invalidate when input files change​

In most common cases, you want to invalidate cache when source files in the project have changed.

In order to do that, you need to pass an inputChanges array.

project.json
{
"targets": {
"my-target": {
"cache": {
"invalidateWhen": {
"inputChanges": [
{
"pattern": "**",
"exclude": [
"node_modules/**"
]
}
]
}
}
}
}
}

The inputChanges invalidation strategy takes an array of matcher objects. Here are the supported options :

  • pattern: The pattern to match against, provided as a string.
  • exclude: Exclusions patterns to apply when matching is performed (defaults to an empty set).
  • root: Override the root directory from where matching occurs (defaults to the project's root directory).
  • behavior: Defines how files are checked for changes (defaults to Mixed). The supported values are :
    • Timestamps: Only check the OS-provided last modification time.
    • Mixed: Compare checksums to confirm if file was indeed modified if the OS-provided last modification time suggests so.
    • Hash: Only check file modifications by using checksums.

You can also provide simple inclusion patterns as raw strings in the inputChanges array.

The inclusion pattern must never start with a / or anything that would match paths from the filesystem root. You can use the root parameter if you want to provide absolute inclusion patterns.

The pattern matching is done using the wax crate. Checkout their documentation to get more details about pattern matching.

The files will be analyzed for changes before execution and the cached files state will be immediately updated if there are changes. If you want file state to be re-analyzed after exection, you can use the outputChanges strategy.

Invalidate when output files change​

The outputChanges strategy can be used to trigger a fresh start if file that is generated by the target is changed afterwards.

This strategy works exactly like the ìnputChanges strategy, the only difference is that the files state is re-analyzed and stored after target execution.

You will have to provide an array of file matcher objects, the options and syntax are the same as documented in the inputChanges strategy.

info

The inputChanges strategy is more optimized and should be preferred over outputChanges. Use outputChanges only when the files that you want to watch are generated by the target itself.

warning

Be careful when watching for changes on build artefacts since they might be a lot of files.

Invalidate after a certain duration​

You can also activate a TTL (Time-To-Live) on a target cache.

You will need to pass an expired key to the invalidateWhen object.

In this example, the cache will expires after a full day (24 hours).

project.json
{
"targets": {
"my-target": {
"cache": {
"invalidateWhen": {
// cache has a 1 day TTL
"expired": {
"unit": "Days",
"amount": 1
}
}
}
}
}
}

The unit parameter supports the following values :

  • Milliseconds
  • Seconds
  • Minutes
  • Hours
  • Days

Invalidate cache if files are missing​

Sometimes you want to force recompilation of some deleted files.

You can provide a list of file system entries to be checked for presence. If any of these files are missing, then cache will be invalidated.

project.json
{
"targets": {
"my-target": {
"cache": {
"invalidateWhen": {
// relaunch if compiled artefact is missing
"filesMissing": [
"dist/bundle.js"
]
}
}
}
}
}

An entry will be considered as missing if it is not a file, a directory, or a symlink.

Relative paths will be considered as from the project's root directory. You can also provide arbitrary absolute paths.

Invalidate when a command fails​

For more complex scenarios, you can write your own invalidation logic by providing a custom command.

If the command fails, the cache will be invalidated.

You can pass an invalidation strategy with a key set to commandFails.

project.json
{
"targets": {
"my-target": {
"cache": {
"invalidateWhen": {
"commandFails": {
"program": "/bin/sh",
"arguments": ["-c", "{{ project.root }}/validate-cache.sh"],
"environment": {
"SOME_ENVIRONMENT_VARIABLE": "1"
}
}
}
}
}
}
}
  • program: The name of the program, provided as a string.
  • arguments: A list of arguments for the program, provided as an array of strings.
  • environment: Environment variables that must be available within the process.
  • verbose: If output should be displayed (defaults to false).
  • cwd: Override the process current directory (defaults to the project's root directory).

The following environment variables are also available :

  • BLAZE_PROJECT: The name of the project on which the target is being executed.
  • BLAZE_TARGET: The name of the executed target.
  • BLAZE_OPTIONS: The options that were passed to the executor, as a raw JSON string.
  • FRESH_EXECUTION: Will be set to true if a cache entry did not exist yet for this target.
  • LAST_EXECUTION_CACHED_AT: A unix timestamp representing the time of the last successful cached execution. This variable will not be set if FRESH_EXECUTION is set.

If the process ends up with a non-zero status code, the cache will be invalidated.

Early process termination with no status code will be considered as a target execution error.

It does not matter if your command returns a non-zero status code when the execution is not yet cached.

This first execution can be used in order to store the cache state.

Command failure means unexpected termination or a non-zero status code.

Invalidate when environment variables change​

Sometimes cache must be invalidated when settings provided through environment variables are modified.

You can list environment variables to watch at the envChanges key :

project.json
{
"targets": {
"my-target": {
"cache": {
"invalidateWhen": {
"envChanges": {
"variables": [
"VAR"
]
}
}
}
}
}
}

In this example, my-target cache will be invalidated if :

  • The VAR environment variable has a value and was previously unset.
  • The VAR environment variable is unset and was previously set.
  • The VAR environment variable has a new value.

Remove cache manually​

The rm-cache command comes in handy when you want to invalidate target execution cache manually and explicitely.

It works similarly to the run and spawn. You indicate a target name and select as many projects as you want.

Here are a few examples :

  • Delete one specific cache entry :
blaze rm-cache my-project:target
  • Delete all entries for the build target :
blaze rm-cache --all -t build

Removing all cache entries is not provided out-of-the-box but it can be achieved with the describe and spawn commands :

blaze spawn --all -- 'for t in $(blaze describe project --summary {{ project.name }}); do blaze rm-cache {{ project.name }}:$t; done'
info

Checkout the rm-cache command documentation for all available options.

warning

Deleting the .blaze/cache directory will remove all cached target executions (as well as cached executors). This method is not the cleanest but it can be used in case of cache corruption or more generally if you are unable to call rm-cache.