Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 6898481

Browse files
Handle asyncio.TimeoutError for link validation code (#1051)
Handle asyncio.TimeoutError
1 parent 9b3059f commit 6898481

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

api/catalog/api/utils/validate_images.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ def _get_expiry(status, default):
3333

3434
async def _head(url: str, session: aiohttp.ClientSession) -> tuple[str, int]:
3535
try:
36-
async with session.head(url, timeout=2, allow_redirects=False) as response:
36+
async with session.head(url, allow_redirects=False) as response:
3737
return url, response.status
38-
except aiohttp.ClientError as exception:
38+
except (aiohttp.ClientError, asyncio.TimeoutError) as exception:
3939
_log_validation_failure(exception)
4040
return url, -1
4141

@@ -44,7 +44,8 @@ async def _head(url: str, session: aiohttp.ClientSession) -> tuple[str, int]:
4444
@async_to_sync
4545
async def _make_head_requests(urls: list[str]) -> list[tuple[str, int]]:
4646
tasks = []
47-
async with aiohttp.ClientSession(headers=HEADERS) as session:
47+
timeout = aiohttp.ClientTimeout(total=2)
48+
async with aiohttp.ClientSession(headers=HEADERS, timeout=timeout) as session:
4849
tasks = [asyncio.ensure_future(_head(url, session)) for url in urls]
4950
responses = asyncio.gather(*tasks)
5051
await responses

api/test/unit/utils/validate_images_test.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import asyncio
12
from unittest import mock
23

34
import aiohttp
@@ -43,4 +44,27 @@ def test_sends_user_agent(wrapped_client_session: mock.AsyncMock):
4344
for url in image_urls:
4445
assert url in requested_urls
4546

46-
wrapped_client_session.assert_called_once_with(headers=HEADERS)
47+
wrapped_client_session.assert_called_once_with(headers=HEADERS, timeout=mock.ANY)
48+
49+
50+
def test_handles_timeout():
51+
"""
52+
Note: This test takes just over 3 seconds to run as it simulates network delay of 3 seconds.
53+
"""
54+
query_hash = "test_handles_timeout"
55+
results = [{"identifier": i} for i in range(1)]
56+
image_urls = [f"https://example.org/{i}" for i in range(len(results))]
57+
start_slice = 0
58+
59+
def raise_timeout_error(*args, **kwargs):
60+
raise asyncio.TimeoutError()
61+
62+
with mock.patch(
63+
"aiohttp.client.ClientSession._request", side_effect=raise_timeout_error
64+
):
65+
validate_images(query_hash, start_slice, results, image_urls)
66+
67+
# `validate_images` directly modifies the results list
68+
# if the results are timing out then they're considered dead and discarded
69+
# so should not appear in the final list of results.
70+
assert len(results) == 0

0 commit comments

Comments
 (0)