Skip to content

perf(conversion): cache conversion chart results for 60s#270

Open
ayushjhanwar-png wants to merge 1 commit into
mainfrom
perf/conversion-skip-previous-period
Open

perf(conversion): cache conversion chart results for 60s#270
ayushjhanwar-png wants to merge 1 commit into
mainfrom
perf/conversion-skip-previous-period

Conversation

@ayushjhanwar-png

@ayushjhanwar-png ayushjhanwar-png commented May 11, 2026

Copy link
Copy Markdown

Summary

Apply the existing `cacheMiddleware(60)` to the conversion TRPC procedure. Conversion queries are the slowest chart type, and repeat dashboard loads currently recompute the full SQL every time.

The middleware already exists in chart.ts:61 and is applied to all overview procedures. The conversion procedure was missing it.

Change

One-line addition between `.input()` and `.query()`:

```ts

  • conversion: protectedProcedure.input(zChartInput).query(async ({ input }) => {
  • conversion: protectedProcedure.input(zChartInput).use(cacher).query(async ({ input }) => {
    ```

How it works

  • Cache key: `trpc:chart.conversion:<JSON.stringify(input)>` — different chart configs (project, date range, breakdowns, cohort filter) get separate entries
  • TTL: 60s (same as the rest of chart.ts's cacher)
  • Cache reads only in production (`NODE_ENV === 'production'` guard in the middleware)
  • Cache writes happen in all environments

What this addresses

Repeat-load doubling: when multiple users open the same chart within 60s, or when a single user reloads the dashboard, only the first load hits ClickHouse. Subsequent loads return from Redis.

What this does NOT address

The parallel current + previous-period query within a single chart load (when `input.previous` is true). That's a separate problem requiring frontend changes to lazy-load the comparison period.

Risks

  • 60s data staleness on conversion charts — analytics dashboards typically tolerate this
  • Cache key uses the full input — if any field is non-deterministic (e.g., a timestamp), cache hits won't work. Should not be the case for `zChartInput` but worth watching
  • Memory pressure on Redis if many distinct chart configs are accessed in 60s windows — bounded by Redis eviction

The conversion TRPC procedure recomputes the full conversion query for
every dashboard load, even when the same chart is opened repeatedly in
quick succession. Repeat opens within a minute end up running the same
40s+ CH query multiple times.

Reuses the existing cacheMiddleware(60) defined in chart.ts (already
applied to overview procedures, just not to conversion). One-line
change: add .use(cacher) between .input() and .query().

Cache key is hash of the full input (project, date range, breakdowns,
cohort, etc.) so different chart configurations get separate entries.
TTL of 60 seconds matches the other cached chart procedures.

This addresses repeat-load doubling. The parallel current + previous
doubling within a single chart load (when input.previous is true) is
a separate problem requiring frontend changes.
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