Skip to content

Commit 2f05e77

Browse files
authored
[CI] Improve reliability of queries against GitHub GraphQL API (llvm#683)
Recently, the workflow for collecting llvm operational data has been failing relatively often due to calls to the GitHub GraphQL API failing. There doesn't seem to be definitive reason, with most responses just being `502 Bad Gateway`. However, reducing the number of commits requested per batch seems to make these calls reliable again. This change also adds retries with some backoff, so the script only fails after trying the GitHub API multiple times. We could also reduce the number of commits we're requesting for each API failure, but just reducing the overall batch size seems to work fine for the time being.
1 parent ab7cbb0 commit 2f05e77

File tree

3 files changed

+66
-16
lines changed

3 files changed

+66
-16
lines changed

premerge/ops-container/process_llvm_commits.py

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import git
88
from google.cloud import bigquery
99
import requests
10+
import retry
1011

1112
GITHUB_GRAPHQL_API_URL = "https://api.github.com/graphql"
1213
REPOSITORY_URL = "https://github.com/llvm/llvm-project.git"
@@ -17,7 +18,7 @@
1718

1819
# How many commits to query the GitHub GraphQL API for at a time.
1920
# Querying too many commits at once often leads to the call failing.
20-
GITHUB_API_BATCH_SIZE = 50
21+
GITHUB_API_BATCH_SIZE = 35
2122

2223
# Number of days to look back for new commits
2324
# We allow some buffer time between when a commit is made and when it is queried
@@ -71,6 +72,10 @@ class LLVMCommitInfo:
7172
commit_reverted: str | None = None
7273

7374

75+
class GitHubAPIError(Exception):
76+
"""Raised when a GitHub GraphQL API call fails."""
77+
78+
7479
def scrape_new_commits_by_date(
7580
target_datetime: datetime.datetime,
7681
) -> list[git.Commit]:
@@ -105,6 +110,46 @@ def scrape_new_commits_by_date(
105110
return new_commits
106111

107112

113+
@retry.retry(
114+
exceptions=(GitHubAPIError, requests.exceptions.ChunkedEncodingError),
115+
tries=5,
116+
delay=1,
117+
backoff=2,
118+
)
119+
def query_github_graphql_api(
120+
query: str,
121+
github_token: str,
122+
) -> requests.Response:
123+
"""Query GitHub GraphQL API, retrying on failure.
124+
125+
Args:
126+
query: The GraphQL query to send to the GitHub API.
127+
github_token: The access token to use with the GitHub GraphQL API.
128+
129+
Returns:
130+
The response from the GitHub GraphQL API.
131+
"""
132+
response = requests.post(
133+
url=GITHUB_GRAPHQL_API_URL,
134+
headers={
135+
"Authorization": f"bearer {github_token}",
136+
},
137+
json={"query": query},
138+
)
139+
140+
# Exit if API call fails
141+
# A failed API call means a large batch of data is missing and will not be
142+
# reflected in the dashboard. The dashboard will silently misrepresent
143+
# commit data if we continue execution, so it's better to fail loudly.
144+
if response.status_code < 200 or response.status_code >= 300:
145+
raise GitHubAPIError(
146+
"[%d] Failed to query GitHub GraphQL API: %s"
147+
% (response.status_code, response.text)
148+
)
149+
150+
return response
151+
152+
108153
def query_for_reviews(
109154
new_commits: list[git.Commit], github_token: str
110155
) -> list[LLVMCommitInfo]:
@@ -189,21 +234,7 @@ def query_for_reviews(
189234
num_batches,
190235
len(subquery_batch),
191236
)
192-
response = requests.post(
193-
url=GITHUB_GRAPHQL_API_URL,
194-
headers={
195-
"Authorization": f"bearer {github_token}",
196-
},
197-
json={"query": query},
198-
)
199-
200-
# Exit if API call fails
201-
# A failed API call means a large batch of data is missing and will not be
202-
# reflected in the dashboard. The dashboard will silently misrepresent
203-
# commit data if we continue execution, so it's better to fail loudly.
204-
if response.status_code < 200 or response.status_code >= 300:
205-
logging.error("Failed to query GitHub GraphQL API: %s", response.text)
206-
exit(1)
237+
response = query_github_graphql_api(query, github_token)
207238

208239
api_commit_data.update(response.json()["data"]["repository"])
209240

premerge/ops-container/requirements.lock.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ charset-normalizer==3.4.2 \
112112
# via
113113
# -r ./requirements.txt
114114
# requests
115+
decorator==5.2.1 \
116+
--hash=sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360 \
117+
--hash=sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a
118+
# via
119+
# -r ./requirements.txt
120+
# retry
115121
gitdb==4.0.12 \
116122
--hash=sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571 \
117123
--hash=sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf
@@ -294,6 +300,12 @@ protobuf==6.31.1 \
294300
# googleapis-common-protos
295301
# grpcio-status
296302
# proto-plus
303+
py==1.11.0 \
304+
--hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \
305+
--hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378
306+
# via
307+
# -r ./requirements.txt
308+
# retry
297309
pyasn1==0.6.1 \
298310
--hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629 \
299311
--hash=sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034
@@ -320,6 +332,10 @@ requests==2.32.4 \
320332
# -r ./requirements.txt
321333
# google-api-core
322334
# google-cloud-bigquery
335+
retry==0.9.2 \
336+
--hash=sha256:ccddf89761fa2c726ab29391837d4327f819ea14d244c232a1d24c67a2f98606 \
337+
--hash=sha256:f8bfa8b99b69c4506d6f5bd3b0aabf77f98cdb17f3c9fc3f5ca820033336fba4
338+
# via -r ./requirements.txt
323339
rsa==4.9.1 \
324340
--hash=sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762 \
325341
--hash=sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75

premerge/ops-container/requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
cachetools==5.5.2
22
certifi==2025.6.15
33
charset-normalizer==3.4.2
4+
decorator==5.2.1
45
gitdb==4.0.12
56
GitPython==3.1.44
67
google-api-core==2.25.1
@@ -16,10 +17,12 @@ idna==3.10
1617
packaging==25.0
1718
proto-plus==1.26.1
1819
protobuf==6.31.1
20+
py==1.11.0
1921
pyasn1==0.6.1
2022
pyasn1_modules==0.4.2
2123
python-dateutil==2.9.0.post0
2224
requests==2.32.4
25+
retry==0.9.2
2326
rsa==4.9.1
2427
six==1.17.0
2528
smmap==5.0.2

0 commit comments

Comments
 (0)