Formula cache#
A formula is normally evaluated every time it is read. For a heavy formula — a deep dependency tree, many fine-granularity (sub-quarter-hour) series pulled over the whole history, or costly operators — this can make reads slow (a sluggish tsinfo). The formula cache materialises the result of such a series: its values are pre-computed and stored, so a read serves them directly instead of re-evaluating the formula.
When to use it#
Cache a formula when it is slow to display, typically because of:
a deep dependency tree;
many fine-granularity series read over a long history;
costly operators (
resample,priority,block-staircase, or multi-site aggregates such asfindseries+add).
How it works#
Three things are worth understanding.
Refresh — the cache is filled and kept up to date by a rework task,
refresh_formula_cache, run on each policy’s schedule (schedule_rule); it walks the policy’s series in dependency order and materialises new revision dates incrementally. Its on-demand counterpart,refresh_formula_cache_now, is behind the Refresh button. Creating a policy and mapping series does not populate the cache — a refresh has to run.Freshness — when a cached series is read, if its cache has not been refreshed for more than about twice its usual cadence, it is considered stale and recomputed live over the policy’s window. In normal operation the cache is served directly, giving a fast read.
Intermediate nodes speed up their parents — when the engine evaluates a formula, it stops expanding the dependency tree as soon as it reaches a cached sub-series and reads the cached values directly. Caching an intermediate node therefore cuts out the computation of everything below it, for every formula that depends on it.
Configuring a policy#
Caching is driven by a policy, which has five parameters:
parameter |
role |
|---|---|
|
earliest revision date to cache from |
|
lower bound of the materialised value window |
|
upper bound of the materialised value window |
|
cron rule: which revision dates to snapshot |
|
cron rule: when the refresh job runs |
initial_revdate, look_before and look_after are date expressions (a
small lisp), evaluated at refresh time — for example (date "2025-01-01"),
(today), (shifted now #:days -60) or (shifted now #:days 15).
The two cron rules serve different purposes: revdate_rule selects which
revision dates to snapshot (e.g. 0 * * * * — every hour on the hour), while
schedule_rule decides when the refresh task actually runs (e.g. 5 * * * *
— five past the hour). The small offset lets data pipelines finish before the
snapshot is taken.
Warning
The value window is the main pitfall. look_before / look_after
define the range of value dates the cache materialises (and that the live
recompute uses). It must cover the whole history you display. A window that
is too narrow (for instance look_before = (today),
look_after = (today)) caches almost nothing, so the cache brings no
benefit. Use a wide range, for example look_before = (date "2025-01-01")
(or (shifted now #:days -180)) and look_after = (shifted now #:days 15).
Examples.
# Hourly cache, a week of revisions, six months of value history
initial_revdate (shifted now #:days -7)
look_before (shifted now #:days -180)
look_after (shifted now #:days 15)
revdate_rule 0 * * * * # snapshot every hour
schedule_rule 5 * * * * # refresh at 5 past the hour
# Once-a-day cache, fixed history start
initial_revdate (date "2025-01-01")
look_before (date "2025-01-01")
look_after (shifted now #:days 15)
revdate_rule 0 6 * * * # one snapshot a day, 06:00
schedule_rule 15 6 * * * # refresh at 06:15
Cache operations#
From the cache management interface:
Refresh — triggers an immediate refresh (the
refresh_formula_cache_nowtask) over the window. It does not purge anything and does not rebuild an emptied cache.Activate / Deactivate — schedules or removes the periodic
refresh_formula_cachetask. A policy can only be edited while it is deactivated.Delete — purges the cache of all the policy’s series and removes the policy and its series mappings (everything has to be recreated).
Free series — moving a series to the free list purges that series’ cache and unmaps it from the policy.
A series’ cache is emptied in three cases: deleting its policy (every series), moving the series to the free list (that series only), and editing its formula — a change to the formula invalidates its own cache and those of its dependents.
Programmatic access#
A policy can be created and populated from the API:
tsa.new_cache_policy(
'daily',
initial_revdate='(shifted now #:days -7)',
look_before='(shifted now #:days -180)',
look_after='(shifted now #:days 15)',
revdate_rule='0 * * * *',
schedule_rule='5 * * * *',
)
tsa.set_cache_policy('daily', ['my.heavy.formula'])
Related methods: cache_policies() and cache_free_series() list the
policies and the formulas still available for caching; cache_series_policy
and has_cache inspect a series; delete_cache clears a series’ cache; and
refresh_series_policy_now triggers an immediate refresh of a policy. See
Formulas (computed series) for the full cache API reference.