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 :
{
"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.
{
"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 toMixed
). 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.
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.
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).
{
"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.
{
"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
.
{
"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 tofalse
).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 totrue
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 ifFRESH_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 :
{
"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'
Checkout the rm-cache
command documentation for all available options.
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
.