Skip to content

perf(server): cache gas-costs and node-sessions reads#16

Open
Sentinel-Bluebuilder wants to merge 1 commit into
masterfrom
feat/server-readcache-gas-sessions
Open

perf(server): cache gas-costs and node-sessions reads#16
Sentinel-Bluebuilder wants to merge 1 commit into
masterfrom
feat/server-readcache-gas-sessions

Conversation

@Sentinel-Bluebuilder

Copy link
Copy Markdown
Owner

What

Two read-heavy LCD endpoints recomputed their full scan on every request. This wraps both in cached() and invalidates on the writes that change them.

GET /api/feegrant/gas-costs

Fires one LCD tx-search per subscriber address — a 900-subscriber plan is ~900 serial 30s-timeout calls (minutes of wall-clock) on every hit.

  • Cache the whole computed result 5 min, keyed gasCosts:<planId>:<operator>. The operator is in the key because the result filters on fee.granter === getAddr(), so a different signer must not read another operator's stale total.
  • Switch the per-address probe loop from one-at-a-time to bounded-concurrency waves (GAS_CONCURRENCY = 8): a cold-cache scan drops from ~N serial calls to ceil(N/8) waves. Capped at 8 to avoid saturating the LCD pool (node scan already runs at 30).

GET /api/nodes/:addr/sessions

Walks up to 50 LCD pages (25k sessions) client-filtering for one node.

  • Cache 2 min, keyed nodeSessions:<addr>.
  • Invalidate that key on start-session success so the next read reflects the new session.

Notes

  • RPC-first stays intact for the subscriptions sub-query; LCD remains fallback only.
  • Response shapes unchanged — pure caching + invalidation, no behavioral change.
  • node --check passes. No non-ASCII edits.

Relationship to other PRs

Part of the four-way split of an intermingled working tree: #13 (audit hardening), #14 (plan-nodes caching), #15 (FE optimistic reconcile), and this PR (server gas/session read caching). Independent of the others — touches only the two routes above.

Two read-heavy LCD endpoints recomputed their full scan on every hit.
Wrap both in cached() with invalidation on the writes that change them.

- GET /api/feegrant/gas-costs: fires one LCD tx-search per subscriber
  address (a 900-subscriber plan = ~900 serial 30s-timeout calls, minutes
  of wall-clock). Cache the whole computed result 5 min keyed by
  gasCosts:<planId>:<operator> — the operator is in the key because the
  result filters on fee.granter === getAddr(), so a different signer must
  not read a stale total. Also switch the per-address probe loop from
  one-at-a-time to bounded-concurrency waves (GAS_CONCURRENCY = 8) so a
  cold-cache scan drops from ~N serial calls to ceil(N/8) waves; cap at 8
  to avoid saturating the LCD pool (node scan already runs at 30).

- GET /api/nodes/:addr/sessions: walks up to 50 LCD pages (25k sessions)
  client-filtering for one node. Cache 2 min keyed by nodeSessions:<addr>.
  Invalidate that key on start-session success so the next read reflects
  the new session.

Read-only RPC-first stays intact for the subscriptions sub-query; LCD is
fallback. No behavior change to response shapes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant