Repository navigation
[CI] Paginate and retry reviewer assignment - #9377
Conversation
The single GraphQL query in scripts/assign_reviewer.py fetched 100 recent PRs with three nested first: 100 connections (latestReviews, reviewRequests, and timelineItems) in one request, which intermittently exceeded GitHub's 10-second GraphQL execution timeout and failed with HTTP 502 (such as on PR #9357 and PR #9368). Split the initial team and target PR lookup into SETUP_QUERY so closed, draft, or already-assigned PRs exit early without fetching PR history, paginate RECENT_PRS_QUERY across two pages of 50 PRs with first: 20 on latestReviews and reviewRequests, and retry transient GitHub API 5xx errors in gh_api with exponential backoff.
There was a problem hiding this comment.
Code Review
This pull request refactors the reviewer assignment script by splitting the monolithic GraphQL query into setup and paginated recent PR queries, reducing requested node limits, and introducing a retry mechanism with exponential backoff for transient GitHub API errors. The review feedback suggests enhancing the retry mechanism by expanding the list of retryable network errors and adopting defensive programming to handle potential null values in the GraphQL response nodes safely.
| RETRYABLE_ERRORS = ( | ||
| 'HTTP 500', | ||
| 'HTTP 502', | ||
| 'HTTP 503', | ||
| 'HTTP 504', | ||
| 'Something went wrong while executing your query', | ||
| ) |
There was a problem hiding this comment.
To make the script more resilient against transient network issues in CI environments, consider expanding RETRYABLE_ERRORS to include common network-level error messages (such as DNS lookup failures, connection timeouts, or connection resets).
| RETRYABLE_ERRORS = ( | |
| 'HTTP 500', | |
| 'HTTP 502', | |
| 'HTTP 503', | |
| 'HTTP 504', | |
| 'Something went wrong while executing your query', | |
| ) | |
| RETRYABLE_ERRORS = ( | |
| 'HTTP 500', | |
| 'HTTP 502', | |
| 'HTTP 503', | |
| 'HTTP 504', | |
| 'Something went wrong while executing your query', | |
| 'dial tcp', | |
| 'i/o timeout', | |
| 'connection refused', | |
| 'TLS handshake', | |
| ) |
| for pr in page['nodes']: | ||
| if pr['number'] not in seen: | ||
| seen.add(pr['number']) | ||
| prs.append(pr) |
There was a problem hiding this comment.
To prevent potential TypeError exceptions if the GraphQL response contains a null value for the nodes field (which can happen under certain partial failure modes in GraphQL), use defensive programming with .get() and a fallback empty list.
| for pr in page['nodes']: | |
| if pr['number'] not in seen: | |
| seen.add(pr['number']) | |
| prs.append(pr) | |
| for pr in page.get('nodes') or []: | |
| if pr['number'] not in seen: | |
| seen.add(pr['number']) | |
| prs.append(pr) |
The single GraphQL query in scripts/assign_reviewer.py fetched 100 recent PRs with three nested first: 100 connections (latestReviews, reviewRequests, and timelineItems) in one request, which intermittently exceeded GitHub's 10-second GraphQL execution timeout and failed with HTTP 502 (such as on PR #9357 and PR #9368).
Split the initial team and target PR lookup into SETUP_QUERY so closed, draft, or already-assigned PRs exit early without fetching PR history, paginate RECENT_PRS_QUERY across two pages of 50 PRs with first: 20 on latestReviews and reviewRequests, and retry transient GitHub API 5xx errors in gh_api with exponential backoff.