fix(admin): stop blocking dashboard tiles on PostHog insight recomputes

Merged
SA
3mo ago
+66-54

Problem

Every insight tile fetched its saved insight with refresh=blocking, which holds the HTTP request open while PostHog recomputes the insight. Timed against the real project on a cold cache:

insightcold
activeOrgs20.3s
activatedRate15.2s
newSiteVisitors9.4s
the other seven0.3–1.0s

Past PostHog's ~15min refresh throttle, loading the Product tab meant a 20s blocking request.

Fix

refresh=blocking → refresh=lazy_async. PostHog serves its cached result immediately and kicks off the recompute in the background. A genuinely cold insight returns no result yet, so fetchInsightResults reports pending and the tile polls until it lands — the same idiom getMrr already uses for Stripe Sigma.

The staleTime + pending-poll wiring is now one useInsightResults hook rather than the identical query block repeated in all four insight tiles.

Measurement

Against the local API with all five Product-tab insights forced to recompute, transport unchanged in both runs:

before (refresh=blocking) — total 18.0s
  + 4.55s  WAU
  + 4.83s  DAU
  + 4.95s  workspacesPerCreator
  + 9.01s  activatedRate
  +18.05s  activeOrgs

after (refresh=lazy_async) — total 0.85s
  all five tiles landed between +0.80s and +0.85s

Notes

  • Tiles now paint last-known numbers first and update when the recompute lands. The tile header already shows lastRefresh, so staleness stays visible.
  • I also checked whether the tRPC batch link was coupling tiles together. It isn't — httpBatchStreamLink streams each result as it resolves (visible in the before-run above, where the fast tiles landed at ~4.5s while activeOrgs was still running). No transport change needed.
  • Two adjacent things left alone: getEnterpriseArr fetches Stripe subscriptions serially in a loop, and the business tiles have no staleTime so they re-run Mercury/Stripe/cohort queries on window refocus.

Summary by cubic

Stops blocking admin dashboard tiles on PostHog recomputes. Old behavior held requests with refresh=blocking; new behavior uses refresh=lazy_async to return cached results immediately and poll during recompute, keeping stale charts visible.

  • Adds useInsightResults(insight) with staleTime=10m; polls every 3s while pending.
  • fetchInsightResults now uses refresh=lazy_async; sets pending when no result or query_status is incomplete; throws on query_status.error so tiles show an error instead of polling forever.
  • Tiles (HogQLLineTile, TrendSeriesTile, RetentionGridTile, PostHogFunnelTile) adopt the hook; show a skeleton only when no result exists; stale numbers stay rendered and update when recompute lands; lastRefresh remains visible.
  • Product tab cold recomputes improve from ~18s to ~0.85s for the last tile to land.

Summary by CodeRabbit

  • New Features

    • Analytics insight tiles now share consistent result loading and refresh behavior.
    • Results automatically update while insights are being recalculated, with refreshes continuing until current data is available.
    • Insight results are reused briefly to improve responsiveness and reduce unnecessary reloads.
  • Bug Fixes

    • Tiles no longer appear complete while results are still pending.
    • Stale results are clearly treated as pending during background recomputation, preventing misleading displays.