Skip to content

pool/records: the month record can be up to 5 minutes stale on the public page #687

Description

@defenwycke

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:

  1. 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.
  2. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions