Skip to content

v3.6.0

Choose a tag to compare

@github-actions github-actions released this 06 Sep 20:46
· 135 commits to main since this release
5dc0ecc

The release that makes a dashboard cheap to serve. Two things the Lodestar cutover measured on
2026-09-06, both performance, neither a new capability; the freeze stands.

A deterministic memo for repeated /sql statements (#1186)

The dashboard's heaviest views are whole-history folds recomputed on every request: after 3.5.1 the
allocations nest still spent 89 s answering its 47 distinct statements serially, 42 s of it in four.
Those statements repeat, and between repeats nothing they read has usually changed.

A /sql answer is a function of its inputs, so the nest now remembers answers under a hash of exactly
those: the statement and its row cap, the sealed watermark, the hot store's write generation (a
counter the store brackets every commit with, so an in-flight commit reads as unknown), each
maintained entity's watermark, and the content of nuthatch.toml, views/*.sql and labels/*.json.
Same key, same rows, by construction; one commit, one seal, one edited view changes the key and the
next request computes. A hit is answered before the permit gate, since it costs no DuckDB, re-reads
the fence after the lookup, cites the provenance its rows were computed under rather than the live
store, and reports "cached": true. Statements calling a volatile function (random(), now(),
current_timestamp and their kin) are computed every time. Degraded and tip-less answers are never
remembered. NUTHATCH_SQL_MEMO_BYTES bounds it (64 MiB default, 0 off); least recently used goes
first; one entry may not take more than a quarter of the ceiling. Metrics:
nuthatch_sql_memo_hits_total, nuthatch_sql_memo_misses_total, nuthatch_sql_memo_bytes.

Measured on a copy of the allocations nest: the dashboard's 47 statements, 99.4 s computed, 0.0 s
remembered (10 ms for the slowest), 736 KB held for the whole panel.

The poll interval holds on a chain that outruns the endpoint (#1190)

Both follow loops slept the interval only when a re-polled tip had stood still. On Arbitrum at four
blocks a second behind a free endpoint that answers slowly, it never had: the gns nest polled every
two seconds under --poll-interval 5m while /ready reported 300, 4,377 CU/min against 121 on the
same chain behind a fast endpoint. The interval now applies the moment a committed window reaches
the ceiling computed from the tip that iteration polled; a window that falls short is a backlog and
loops at once. On a paid endpoint this was the whole bill coming back the day the endpoint slowed.