Skip to content

Closed/merged PR webview panel continues polling LatestUpdates every 60s, exhausting GraphQL rate limit #8667

@rkryo

Description

@rkryo

Summary

When a pull request's webview panel is left open in VS Code after the PR has been closed/merged on GitHub, the extension continues to poll LatestUpdates every webviewRefreshInterval seconds (default: 60s) indefinitely. Each poll consumes a significant number of GraphQL rate limit points proportional to the PR's timeline event count, eventually exhausting the 5,000 points/hour limit.

This is distinct from #7816 (rapid refresh loop on open PR, fixed in v0.120.0) — the polling frequency here is normal (60s), but it never stops even after the PR is closed.

Extension Version

  • Extension version: 0.134.0
  • VS Code Version: 1.115.0
  • OS: macOS (arm64)
  • GitHub Product: GitHub.com

Steps to Reproduce

  1. Open a pull request's description panel in VS Code (click on a PR in the GitHub Pull Requests sidebar)
  2. Close or merge the pull request on GitHub (via the web UI or gh CLI)
  3. Do not close the webview panel in VS Code — leave it open
  4. Wait 1–2 minutes and observe the extension output log (Output > GitHub Pull Request)

Expected Behavior

Once a PR is closed/merged, the extension should either:

  • Stop polling LatestUpdates for that panel entirely, or
  • Significantly reduce the polling frequency (e.g., fall back to 300s or stop)

Actual Behavior

The extension continues to fire LatestUpdates every 60 seconds indefinitely, regardless of the PR's closed state.

From the extension output log (with githubPullRequests.logLevel: debug):

2026-04-14 18:14:46 [warning] [RateLimit] GraphQL Rate limit remaining: 912, cost: 1, LatestUpdates
2026-04-14 18:15:47 [warning] [RateLimit] GraphQL Rate limit remaining: 784, cost: 1, LatestUpdates
2026-04-14 18:16:48 [warning] [RateLimit] GraphQL Rate limit remaining: 657, cost: 1, LatestUpdates
2026-04-14 18:17:49 [warning] [RateLimit] GraphQL Rate limit remaining: 531, cost: 1, LatestUpdates
2026-04-14 18:18:49 [warning] [RateLimit] GraphQL Rate limit remaining: 405, cost: 1, LatestUpdates
2026-04-14 18:19:50 [warning] [RateLimit] GraphQL Rate limit remaining: 277, cost: 1, LatestUpdates
2026-04-14 18:20:51 [warning] [RateLimit] GraphQL Rate limit remaining: 155, cost: 1, LatestUpdates
2026-04-14 18:21:52 [warning] [RateLimit] GraphQL Rate limit remaining: 21,  cost: 1, LatestUpdates
2026-04-14 18:22:52 [error]   Error querying GraphQL API (LatestUpdates): API rate limit already exceeded
2026-04-14 18:22:52 [error]   [IssueModel] Error fetching timeline events of issue #295 - API rate limit already exceeded

The log shows IssueModel Error fetching timeline events of issue #295 — where PR #295 was closed approximately 6 hours prior. The poll fires exactly every 60 seconds and does not stop.

Rate Limit Impact

Each LatestUpdates call for this closed PR consumes approximately 128 GraphQL points (proportional to the number of timeline events on the PR). At 60-second intervals:

  • ~128 pts/min x 60 = ~7,680 pts/hour — exceeds the 5,000 pts/hour limit by itself
  • When combined with normal sidebar queries (MaxPullRequest every few minutes), the rate limit is exhausted within minutes of the session starting

Related: Concurrent call burst (also observed, related to #8621)

In the same session, when a rate limit error occurred during a normal sidebar refresh, the extension fired 15 individual PullRequest queries simultaneously (within 300ms):

2026-04-14 18:23:24.125 [error] Error querying GraphQL API (PullRequest): rate limit already exceeded
2026-04-14 18:23:24.134 [error] Error querying GraphQL API (PullRequest): rate limit already exceeded
2026-04-14 18:23:24.134 [error] Error querying GraphQL API (PullRequest): rate limit already exceeded
2026-04-14 18:23:24.135 [error] Error querying GraphQL API (PullRequest): rate limit already exceeded
2026-04-14 18:23:24.144 [error] Error querying GraphQL API (PullRequest): rate limit already exceeded
... (15 total within 300ms)

This matches the pattern in #8621 and appears to be a separate race condition triggered when the sidebar attempts to reload after a refresh cycle.

Suggested Fix

In pollForUpdates (or wherever LatestUpdates is scheduled), check the PR's state before scheduling the next poll. If state === 'closed' or state === 'merged', either cancel the timer or set the interval to a significantly longer value (e.g., stop entirely or use 3600s).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions