Skip to content

perf: dedupe PR thread fetches across tree + notification poll#67

Open
CompN3rd wants to merge 2 commits into
mainfrom
perf/pr-fanout
Open

perf: dedupe PR thread fetches across tree + notification poll#67
CompN3rd wants to merge 2 commits into
mainfrom
perf/pr-fanout

Conversation

@CompN3rd
Copy link
Copy Markdown
Owner

Introduces PrThreadCache \u2014 a small TTL (30s) + in-flight-promise dedup map keyed on org/project/repo/prId. Wires the same instance into both PullRequestProvider and PrCommentHandler.

Problem

Before this change, comment threads were re-fetched aggressively:

  • The notification poller (default 60s, minimum 60s) fetched threads for every active PR each tick.
  • A tree expand on the same PR seconds later issued a fresh request.
  • Two concurrent expands of the same PR (e.g. refresh-while-expanding) hit ADO twice.

After

  • Poll tick populates the cache. A tree expand within 30s is served from memory.
  • Concurrent getOrFetch for the same PR share one in-flight promise \u2014 second caller waits for the first request.
  • Tree refresh (full or per-bucket) clears the cache so user-triggered refreshes always see fresh data.

Design notes

  • TTL of 30s is shorter than the minimum poll interval (60s) so the next poll tick always returns fresh data; the cache exists purely to absorb same-second duplicate work.
  • Cache is optional in both constructors (PullRequestProvider, PrCommentHandler). Callers that don't pass one fall back to the existing direct call path; useful for tests and keeps the diff small.
  • Class-level docstring documents the cross-system invariant (must be one shared instance) since this is non-obvious from constructor signatures.

Files

  • new src/providers/prThreadCache.ts
  • src/providers/pullRequestProvider.ts \u2014 optional threadCache ctor param; loadThreads routes through it; refresh/refreshBucket clear it
  • src/notifications/handlers/prCommentHandler.ts \u2014 optional _threadCache ctor param; pollPullRequests routes through it
  • src/extension.ts \u2014 constructs single PrThreadCache and passes to both consumers

Verification

  • npm run compile clean
  • npm run lint clean

Introduce PrThreadCache: a small TTL (30s) + in-flight-promise dedup map
keyed on org/project/repo/prId. Wire the same instance into both
PullRequestProvider and PrCommentHandler.

Before: each notification poll tick fetched threads for every active PR,
and any subsequent tree expand within seconds re-fetched the same data.
Multiple concurrent expands of the same PR (refresh-while-expanding)
also issued duplicate requests.

After: poll populates the cache; tree expand within 30s is served from
memory; concurrent fetches share one in-flight promise. Tree refresh
(full or per-bucket) invalidates the cache so user-triggered refreshes
still see fresh data.

Cache is optional in both constructors to keep callers without DI happy.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a shared, short-lived cache for PR comment threads to reduce redundant Azure DevOps API calls across the Pull Requests tree view and the PR comment notification poller, including deduplication of concurrent fetches via shared in-flight promises.

Changes:

  • Added PrThreadCache (30s TTL + in-flight promise dedup) keyed by org/project/repo/prId.
  • Wired a single PrThreadCache instance into both PullRequestProvider and PrCommentHandler.
  • Cleared the cache on tree refresh / bucket refresh to keep user-triggered refresh behavior consistent.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/providers/pullRequestProvider.ts Uses PrThreadCache.getOrFetch() when available and clears cache on refresh actions.
src/providers/prThreadCache.ts New TTL + in-flight dedup cache implementation for PR comment threads.
src/notifications/handlers/prCommentHandler.ts Routes thread polling through PrThreadCache when provided.
src/extension.ts Creates one shared PrThreadCache instance and passes it to both consumers.

Comment thread src/providers/prThreadCache.ts Outdated
Comment on lines +35 to +38
* Consumers (tree provider, notification poll, details panel, diff controller)
* all hit the same instance via `getOrFetch`. Within the TTL window, repeat
* calls return cached data; concurrent calls for the same PR share a single
* in-flight promise so we never issue duplicate ADO requests.
Comment on lines +52 to +64
get(k: PrThreadKey): GitPullRequestCommentThread[] | undefined {
const entry = this.entries.get(keyOf(k));
if (!entry) { return undefined; }
if (entry.expires <= Date.now()) {
this.entries.delete(keyOf(k));
return undefined;
}
return entry.threads;
}

set(k: PrThreadKey, threads: GitPullRequestCommentThread[]): void {
this.entries.set(keyOf(k), { threads, expires: Date.now() + this.ttlMs });
}
}

clear(): void {
this.entries.clear();
- clear() now also drops in-flight promises so an active fetch can't
  repopulate the cache with stale data after a refresh
- set() opportunistically sweeps expired entries to bound memory growth
- docstring corrected to list only the wired consumers
  (PullRequestProvider, PrCommentHandler); details panel and diff
  controller were aspirational
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