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 as findseries + 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

initial_revdate

earliest revision date to cache from

look_before

lower bound of the materialised value window

look_after

upper bound of the materialised value window

revdate_rule

cron rule: which revision dates to snapshot

schedule_rule

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.

../_images/cache_policy_form.png

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_now task) over the window. It does not purge anything and does not rebuild an emptied cache.

  • Activate / Deactivate — schedules or removes the periodic refresh_formula_cache task. 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.