What
1e7235b6c memoised GET /api/v1/pool/records per window to stop a 7–30 s query running on every request. The TTLs (records_ttl, routes.rs):
| window |
TTL |
month |
300 s |
week |
120 s |
day |
60 s |
block / unrecognised |
15 s |
So a newly-found record can take up to 5 minutes to appear on the public page in the month window, and up to 2 minutes in the week window.
Why it was done this way
The underlying query cannot be made cheap by rewriting. Ranking by rarity means reverse_hex(share_hash) over every row in the window — a function of the column, so no index can serve the ORDER BY. Pre-aggregating each arm of shares_all separately only moved it 39.5 s → 24.6 s. Measured on ghost-vm6 (4 GB RAM, 4.5 GB database):
records?window=month, cold 19.7 s (up to 40 s under load)
records?window=day 0.059 s
records?window=block 0.006 s
Without the memo, ghost-web asked all eight nodes for this every 60 s, which kept the fleet close to permanently busy.
⚠ This cost predates the share-shard cutover: shares_archive alone (the exact pre-v56 shape) was 30,455 ms vs 40,780 ms through shares_all. v56 made it ~34% worse, it did not create it.
Why the staleness is tolerable, but should not be permanent
A record can only ever improve within its window (a rarer share appears) or age out, so a stale answer is a conservative one — never a wrong kind of value. The client already tolerates exactly this: pool.html caches records itself and enforces window monotonicity, because vm6 had been returning 504 on month at nginx's proxy_read_timeout 10s for some time before any of this.
But "the public page can be five minutes behind on a headline number" is a workaround, not a design.
The actual fix
Make the query cheap, then drop the TTL to something small:
- A maintained records table. A background task computes best-per-window on a schedule and writes a tiny table the endpoint reads instantly. No schema surgery on
shares_archive.
- A stored display-order hash column with an index. Lets the ORDER BY use an index and terminate early. Structurally the better answer, but it means backfilling ~2M rows on nodes with 3.8 GB RAM — the same reason migration v56 deliberately avoided rebuilding indexes at startup.
Residual behaviour to be aware of until then
A cold memo still costs 3–10 s, and on the slowest node that can exceed nginx's 10 s proxy timeout and return 504 — roughly once per 5 minutes. The other nodes answer and the client's cache covers it, so the page stays populated, but it is visible in the access log.
What
1e7235b6cmemoisedGET /api/v1/pool/recordsper window to stop a 7–30 s query running on every request. The TTLs (records_ttl,routes.rs):monthweekdayblock/ unrecognisedSo a newly-found record can take up to 5 minutes to appear on the public page in the month window, and up to 2 minutes in the week window.
Why it was done this way
The underlying query cannot be made cheap by rewriting. Ranking by rarity means
reverse_hex(share_hash)over every row in the window — a function of the column, so no index can serve the ORDER BY. Pre-aggregating each arm ofshares_allseparately only moved it 39.5 s → 24.6 s. Measured on ghost-vm6 (4 GB RAM, 4.5 GB database):Without the memo, ghost-web asked all eight nodes for this every 60 s, which kept the fleet close to permanently busy.
⚠ This cost predates the share-shard cutover:
shares_archivealone (the exact pre-v56 shape) was 30,455 ms vs 40,780 ms throughshares_all. v56 made it ~34% worse, it did not create it.Why the staleness is tolerable, but should not be permanent
A record can only ever improve within its window (a rarer share appears) or age out, so a stale answer is a conservative one — never a wrong kind of value. The client already tolerates exactly this:
pool.htmlcaches records itself and enforces window monotonicity, because vm6 had been returning 504 on month at nginx'sproxy_read_timeout 10sfor some time before any of this.But "the public page can be five minutes behind on a headline number" is a workaround, not a design.
The actual fix
Make the query cheap, then drop the TTL to something small:
shares_archive.Residual behaviour to be aware of until then
A cold memo still costs 3–10 s, and on the slowest node that can exceed nginx's 10 s proxy timeout and return 504 — roughly once per 5 minutes. The other nodes answer and the client's cache covers it, so the page stays populated, but it is visible in the access log.