Skip to content

Commit 78fa10d

Browse files
authored
[ISD-3791] Fix: Add timeouts for ghapi calls (#586)
1 parent dc36d61 commit 78fa10d

File tree

2 files changed

+27
-6
lines changed

2 files changed

+27
-6
lines changed

github-runner-manager/src/github_runner_manager/github_client.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import logging
1010
from datetime import datetime
1111
from typing import Callable, ParamSpec, TypeVar
12-
from urllib.error import HTTPError
12+
from urllib.error import HTTPError, URLError
1313

1414
import requests
1515

@@ -39,6 +39,8 @@
3939

4040
logger = logging.getLogger(__name__)
4141

42+
TIMEOUT_IN_SECS = 60
43+
4244

4345
class GithubRunnerNotFoundError(Exception):
4446
"""Represents an error when the runner could not be found on GitHub."""
@@ -77,6 +79,7 @@ def wrapper(*args: ParamT.args, **kwargs: ParamT.kwargs) -> ReturnT:
7779
"""
7880
try:
7981
return func(*args, **kwargs)
82+
# The ghapi module uses urllib. The HTTPError and URLError are urllib exceptions.
8083
except HTTPError as exc:
8184
if exc.code in (401, 403):
8285
if exc.code == 401:
@@ -86,9 +89,15 @@ def wrapper(*args: ParamT.args, **kwargs: ParamT.kwargs) -> ReturnT:
8689
raise TokenError(msg) from exc
8790
logger.warning("Error in GitHub request: %s", exc)
8891
raise PlatformApiError from exc
92+
except URLError as exc:
93+
logger.warning("General error in GitHub request: %s", exc)
94+
raise PlatformApiError from exc
8995
except RequestException as exc:
9096
logger.warning("Error in GitHub request: %s", exc)
9197
raise PlatformApiError from exc
98+
except TimeoutError as exc:
99+
logger.warning("Timeout in GitHub request: %s", exc)
100+
raise PlatformApiError from exc
92101

93102
return wrapper
94103

@@ -124,11 +133,11 @@ def get_runner(self, path: GitHubPath, prefix: str, runner_id: int) -> SelfHoste
124133
try:
125134
if isinstance(path, GitHubRepo):
126135
raw_runner = self._client.actions.get_self_hosted_runner_for_repo(
127-
path.owner, path.repo, runner_id
136+
path.owner, path.repo, runner_id, timeout=TIMEOUT_IN_SECS
128137
)
129138
else:
130139
raw_runner = self._client.actions.get_self_hosted_runner_for_org(
131-
path.org, runner_id
140+
path.org, runner_id, timeout=TIMEOUT_IN_SECS
132141
)
133142
except HTTP404NotFoundError as err:
134143
raise GithubRunnerNotFoundError from err
@@ -164,6 +173,7 @@ def list_runners(self, path: GitHubPath, prefix: str) -> list[SelfHostedRunner]:
164173
owner=path.owner,
165174
repo=path.repo,
166175
per_page=100,
176+
timeout=TIMEOUT_IN_SECS,
167177
)
168178
for item in page["runners"]
169179
]
@@ -179,6 +189,7 @@ def list_runners(self, path: GitHubPath, prefix: str) -> list[SelfHostedRunner]:
179189
num_of_pages + 1,
180190
org=path.org,
181191
per_page=100,
192+
timeout=TIMEOUT_IN_SECS,
182193
)
183194
for item in page["runners"]
184195
]
@@ -217,6 +228,7 @@ def get_runner_registration_jittoken(
217228
name=instance_id.name,
218229
runner_group_id=1,
219230
labels=labels,
231+
timeout=TIMEOUT_IN_SECS,
220232
)
221233
elif isinstance(path, GitHubOrg):
222234
# We cannot cache it in here, as we are running in a forked process.
@@ -227,6 +239,7 @@ def get_runner_registration_jittoken(
227239
name=instance_id.name,
228240
runner_group_id=runner_group_id,
229241
labels=labels,
242+
timeout=TIMEOUT_IN_SECS,
230243
)
231244
else:
232245
assert_never(token)
@@ -249,7 +262,7 @@ def _get_runner_group_id(self, org: GitHubOrg) -> int:
249262
"Authorization": f"Bearer {self._token}",
250263
"X-GitHub-Api-Version": "2022-11-28",
251264
}
252-
response = requests.get(url, headers=headers, timeout=30)
265+
response = requests.get(url, headers=headers, timeout=TIMEOUT_IN_SECS)
253266
response.raise_for_status()
254267
data = response.json()
255268
try:
@@ -282,11 +295,13 @@ def delete_runner(self, path: GitHubPath, runner_id: int) -> None:
282295
owner=path.owner,
283296
repo=path.repo,
284297
runner_id=runner_id,
298+
timeout=TIMEOUT_IN_SECS,
285299
)
286300
else:
287301
self._client.actions.delete_self_hosted_runner_from_org(
288302
org=path.org,
289303
runner_id=runner_id,
304+
timeout=TIMEOUT_IN_SECS,
290305
)
291306
# The function delete_self_hosted_runner fails in GitHub if the runner does not exist,
292307
# so we do not have to worry about that.
@@ -310,7 +325,12 @@ def get_job_info_by_runner_name(
310325
Returns:
311326
Job information.
312327
"""
313-
paged_kwargs = {"owner": path.owner, "repo": path.repo, "run_id": workflow_run_id}
328+
paged_kwargs = {
329+
"owner": path.owner,
330+
"repo": path.repo,
331+
"run_id": workflow_run_id,
332+
"timeout": 60,
333+
}
314334
try:
315335
for wf_run_page in paged(
316336
self._client.actions.list_jobs_for_workflow_run, **paged_kwargs
@@ -353,6 +373,7 @@ def get_job_info(self, path: GitHubRepo, job_id: str) -> JobInfo:
353373
owner=path.owner,
354374
repo=path.repo,
355375
job_id=job_id,
376+
timeout=TIMEOUT_IN_SECS,
356377
)
357378
except HTTPError as exc:
358379
if exc.code == 404:

github-runner-manager/tests/unit/test_github_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ def raise_for_status(self):
517517

518518
instance_id = InstanceID.build("test-runner")
519519

520-
def _mock_generate_runner_jitconfig_for_org(org, name, runner_group_id, labels):
520+
def _mock_generate_runner_jitconfig_for_org(org, name, runner_group_id, labels, timeout):
521521
"""Mocked generate_runner_jitconfig_for_org."""
522522
assert org == "theorg"
523523
assert name == instance_id.name

0 commit comments

Comments
 (0)