Skip to content

perf(detail): react.cache Copilot calls + skip client refire#1215

Merged
priosshrsth merged 9 commits into
feature/c1-optimizationfrom
anit/out-3701-optimize-task-detail-page
May 12, 2026
Merged

perf(detail): react.cache Copilot calls + skip client refire#1215
priosshrsth merged 9 commits into
feature/c1-optimizationfrom
anit/out-3701-optimize-task-detail-page

Conversation

@priosshrsth
Copy link
Copy Markdown
Collaborator

@priosshrsth priosshrsth commented May 11, 2026

Ref: OUT-3701

Foundation for the detail-page perf work. Two low-risk changes that the deeper refactor in the stacked PR builds on.

Changes

  • CopilotAPI — wrap getInternalUser + getWorkspace in react.cache. Per-request memoization deduplicates Copilot calls within a single RSC / route handler invocation. Falls back to no-op in non-request contexts (jobs, CLI).
  • OneTaskDataFetcher — new useFallback prop that seeds SWR with the SSR-rendered task and disables revalidateOnMount. Default behavior unchanged; the detail page opts in via the stacked PR.

Measured impact

Validated dedup: 4 call sites of getInternalUser(self) collapse to 1 actual network fetch on a typical detail-page load.

Test plan

  • Detail page loads for IU + client tokens
  • Mutations to task (title, body, assignee, workflow state) still work
  • Non-detail pages (home, configure) unaffected

Stacked PR

The actual page handler refactor lives in #1214 (against this branch).

🤖 Generated with Claude Code

Per-request memoization deduplicates Copilot API calls within a single
RSC / route handler invocation. Validated in measurement: 4 call sites
of getInternalUser(self) collapsed to 1 actual network fetch on the
detail page.

Falls back to no-op outside a request context (CLI scripts, Trigger.dev
jobs) so unrelated code paths are unaffected. Cache key includes the
optional customApiKey so workspace-key-override calls don't collide.
When set, seeds SWR with the SSR-rendered initialTask and disables
revalidateOnMount, eliminating the redundant client-side refire of
/api/tasks/{id} after hydration. Caller opts in via the new prop; the
default behavior is unchanged so existing call sites continue to
revalidate as before.
@linear-code
Copy link
Copy Markdown

linear-code Bot commented May 11, 2026

OUT-3701

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 11, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tasks-app Ready Ready Preview, Comment May 12, 2026 7:11am

Request Review

…s-app into anit/out-3701-optimize-task-detail-page
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 12, 2026

Deployment failed with the following error:

Deploying Serverless Functions to multiple regions is restricted to the Pro and Enterprise plans.

Learn More: https://vercel.link/multiple-function-regions

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 12, 2026

Greptile Summary

This PR introduces two low-risk performance foundations for the detail-page work: react.cache wrapping of getInternalUser/getWorkspace for per-request memoization, and a useFallback prop on OneTaskDataFetcher that seeds SWR with the SSR task and suppresses the mount-time refetch.

  • CopilotAPI.ts: Module-level cachedFetchInternalUser/cachedFetchWorkspace use react.cache to deduplicate Copilot calls within a single RSC render pass; customApiKey is promoted to a class field to make its value available to those functions, and getWorkspace/getInternalUser are rewired to the cached variants.
  • OneTaskDataFetcher.tsx: A new useFallback optional prop passes fallbackData + revalidateOnMount: false to SWR, and a useEffect proactively overwrites any stale SWR cache entry on mount so that a fresh SSR render is not silently lost on client-side revisits.

Confidence Score: 5/5

Safe to merge — both changes are additive and opt-in, with no modification to existing call paths for non-fallback consumers.

The react.cache wrappers are purely additive: wrapWithRetry is still used for every other method, and the two rewired methods delegate to the same underlying _ functions via the same withRetry budget. The useFallback prop defaults to undefined/falsy, leaving the existing SWR behaviour fully intact for all current call sites. The proactive mutate in the effect correctly addresses the revisit-stale-cache edge case raised in the prior review thread.

No files require special attention.

Important Files Changed

Filename Overview
src/utils/CopilotAPI.ts Adds react.cache-wrapped module-level functions for getInternalUser/getWorkspace; promotes customApiKey to class field; minor cleanup (remove redundant await, for-of const). Logic is sound and changes are well-scoped.
src/app/_fetchers/OneTaskDataFetcher.tsx Adds useFallback prop to opt into SSR-seeded SWR; useEffect mutate correctly addresses the stale-cache-on-revisit problem flagged in prior review. Default code path is unchanged.

Sequence Diagram

sequenceDiagram
    participant RSC as RSC (detail page)
    participant CA as CopilotAPI
    participant Cache as react.cache
    participant Copilot as Copilot Network

    RSC->>CA: getInternalUser("self") [call site 1]
    CA->>Cache: cachedFetchInternalUser(token, key, "self")
    Cache->>Copilot: _getInternalUser("self") + withRetry
    Copilot-->>Cache: InternalUsers
    Cache-->>CA: cached result
    CA-->>RSC: InternalUsers

    RSC->>CA: getInternalUser("self") [call site 2]
    CA->>Cache: cachedFetchInternalUser(token, key, "self")
    Cache-->>CA: memoized (no network call)
    CA-->>RSC: InternalUsers

    RSC->>CA: getWorkspace() [call site 1]
    CA->>Cache: cachedFetchWorkspace(token, key)
    Cache->>Copilot: _getWorkspace() + withRetry
    Copilot-->>Cache: WorkspaceResponse
    Cache-->>CA: cached result
    CA-->>RSC: WorkspaceResponse

    RSC->>CA: getWorkspace() [call site 2]
    CA->>Cache: cachedFetchWorkspace(token, key)
    Cache-->>CA: memoized (no network call)
    CA-->>RSC: WorkspaceResponse
Loading

Reviews (2): Last reviewed commit: "fix(detail): seed SWR cache with fresh i..." | Re-trigger Greptile

Comment thread src/app/_fetchers/OneTaskDataFetcher.tsx Outdated
Comment thread src/utils/CopilotAPI.ts Outdated
Without this, a stale SWR cache entry from an earlier visit beats the
fresh SSR render: fallbackData only applies when cache is empty, and
revalidateOnMount: false suppresses the refetch. Mutate the cache with
initialTask on mount so the latest SSR data wins.
@priosshrsth
Copy link
Copy Markdown
Collaborator Author

@greptileai review the PR again. regarding the cache memoizing the error. If it throws error even after 3 retries then we already have an issue. So That is expected.

Comment thread src/app/_fetchers/OneTaskDataFetcher.tsx Outdated
Comment thread src/utils/CopilotAPI.ts
Copy link
Copy Markdown
Collaborator

@SandipBajracharya SandipBajracharya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

The only call site (detail page) never passed useFallback, so the
fallbackData + revalidateOnMount: false branch and the mutate-on-mount
seed effect were dead code. Removing them also drops the stale SWR
cache concern, since SWR now revalidates on mount as normal.
@priosshrsth priosshrsth merged commit 9dc91a3 into feature/c1-optimization May 12, 2026
3 checks passed
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.

2 participants