You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Reported alongside #341: selecting the Donor tab in Analytics takes a long time to show anything. Same symptom, different cause — this one is not the donation scan, so the fix in #341 will not touch it.
The slowest call is started last, and it depends on nothing
fetch_global_app_specs_raw() is by a wide margin the most expensive thing the tab does — and it sits in wave 3, behind two full waves of waiting, even though it takes no arguments and depends on no earlier result.
Only one real data dependency exists in the whole effect: fetch_total_network_utils(stage1) needs stage1 from fetch_global_stats. Everything else is independent:
fetch_donor_nodes(donorWallet) — needs only the wallet, known up front
fetch_donor_utilization_source() — no arguments
fetch_global_stats(null) — explicitly passed null
fetch_global_app_specs_raw() — no arguments
So the critical path should be two waves, not three:
That hides the 5–15s spec fetch behind the ~3s of fluxinfo work happening anyway, instead of adding to it.
Nothing survives leaving the tab
networkNodes.js:40 sets RESULT_TTL_MS = 60 * 1000, and _shared() keeps its result in a module-level variable — in-memory only. Exactly the shape #341 describes for the donation scan. Leave the tab for more than a minute, or reload, and all four fluxinfo projections are re-fetched from scratch.
fetch_global_app_specs_raw() is the exception and shows what good looks like: api/specs.js already persists to localStorage under homeAppSpecsRaw_v1 with a 5-minute TTL and a trimmed payload. A warm spec cache makes this tab feel fine; a cold one is the 15-second case.
Proposal
Flatten the waterfall to two waves. Pure reordering, no caching involved, no behaviour change — the largest single win and by far the cheapest to make.
Render progressively rather than all-or-nothing.setLoading(false) fires only after the last wave, so the nodes table — resolved in wave 1 — is withheld until the spec fetch lands. Nodes and utilisation should paint as they arrive; only the apps table needs to wait on specs.
Persist the fluxinfo projections, as Donation section reloads from scratch on every return to Home: 19 sequential explorer requests behind a 60s in-memory TTL #341 proposes for the donation scan. benchmark is 3.9 MB uncompressed, so it must be trimmed to the fields actually read before anything is written — _trimSpecForCache in api/specs.js is the precedent. Measure before committing to this one; if a trimmed benchmark still will not fit comfortably, persist apps.resources,ip only and leave benchmark network-bound.
Do 1 and 2 first and re-measure. They are low-risk and may well be enough on their own, which would make 3 unnecessary.
Acceptance
The donor nodes table renders without waiting on globalappsspecifications
Independent fetches are issued concurrently; only fetch_total_network_utils waits on fetch_global_stats
Switching away from the Donor tab and back does not re-run the full load
cancelled still guards every setState after an await, and switching wallets mid-load still discards the stale response
Related: #341 (same class of problem on Home, different data path).
Reported alongside #341: selecting the Donor tab in Analytics takes a long time to show anything. Same symptom, different cause — this one is not the donation scan, so the fix in #341 will not touch it.
The load is three sequential waves
client/src/analytics/DonorTab/index.jsx:645:Measured, cold:
fluxinfo?projection=benchmarkfluxinfo?projection=apps.resources,ipglobalappsspecificationsThe slowest call is started last, and it depends on nothing
fetch_global_app_specs_raw()is by a wide margin the most expensive thing the tab does — and it sits in wave 3, behind two full waves of waiting, even though it takes no arguments and depends on no earlier result.Only one real data dependency exists in the whole effect:
fetch_total_network_utils(stage1)needsstage1fromfetch_global_stats. Everything else is independent:fetch_donor_nodes(donorWallet)— needs only the wallet, known up frontfetch_donor_utilization_source()— no argumentsfetch_global_stats(null)— explicitly passednullfetch_global_app_specs_raw()— no argumentsSo the critical path should be two waves, not three:
That hides the 5–15s spec fetch behind the ~3s of fluxinfo work happening anyway, instead of adding to it.
Nothing survives leaving the tab
networkNodes.js:40setsRESULT_TTL_MS = 60 * 1000, and_shared()keeps its result in a module-level variable — in-memory only. Exactly the shape #341 describes for the donation scan. Leave the tab for more than a minute, or reload, and all four fluxinfo projections are re-fetched from scratch.fetch_global_app_specs_raw()is the exception and shows what good looks like:api/specs.jsalready persists tolocalStorageunderhomeAppSpecsRaw_v1with a 5-minute TTL and a trimmed payload. A warm spec cache makes this tab feel fine; a cold one is the 15-second case.Proposal
setLoading(false)fires only after the last wave, so the nodes table — resolved in wave 1 — is withheld until the spec fetch lands. Nodes and utilisation should paint as they arrive; only the apps table needs to wait on specs.benchmarkis 3.9 MB uncompressed, so it must be trimmed to the fields actually read before anything is written —_trimSpecForCacheinapi/specs.jsis the precedent. Measure before committing to this one; if a trimmedbenchmarkstill will not fit comfortably, persistapps.resources,iponly and leavebenchmarknetwork-bound.Do 1 and 2 first and re-measure. They are low-risk and may well be enough on their own, which would make 3 unnecessary.
Acceptance
globalappsspecificationsfetch_total_network_utilswaits onfetch_global_statscancelledstill guards everysetStateafter an await, and switching wallets mid-load still discards the stale responseRelated: #341 (same class of problem on Home, different data path).