Skip to content

Commit e9f3f03

Browse files
[PR #10529/492f63dc backport][3.11] Fixed bug that lead to infinite wait for dns futures (#10559)
**This is a backport of PR #10529 as merged into master (492f63d).** <!-- Thank you for your contribution! --> ## What do these changes do? Fixed bug that lead to infinite wait for dns futures when exception occured in trace.send_dns_cache_miss call. ## Are there changes in behavior for the user? No ## Is it a substantial burden for the maintainers to support this? No ## Related issue number No issue. ## Checklist - [x] I think the code is well written - [x] Unit tests for the changes exist - [x] Documentation reflects the changes - [x] If you provide code modification, please add yourself to `CONTRIBUTORS.txt` * The format is &lt;Name&gt; &lt;Surname&gt;. * Please keep alphabetical order, the file is sorted by names. - [x] Add a new news fragment into the `CHANGES/` folder * name it `<issue_or_pr_num>.<type>.rst` (e.g. `588.bugfix.rst`) * if you don't have an issue number, change it to the pull request number after creating the PR * `.bugfix`: A bug fix for something the maintainers deemed an improper undesired behavior that got corrected to match pre-agreed expectations. * `.feature`: A new behavior, public APIs. That sort of stuff. * `.deprecation`: A declaration of future API removals and breaking changes in behavior. * `.breaking`: When something public is removed in a breaking way. Could be deprecated in an earlier release. * `.doc`: Notable updates to the documentation structure or build process. * `.packaging`: Notes for downstreams about unobvious side effects and tooling. Changes in the test invocation considerations and runtime assumptions. * `.contrib`: Stuff that affects the contributor experience. e.g. Running tests, building the docs, setting up the development environment. * `.misc`: Changes that are hard to assign to any of the above categories. * Make sure to use full sentences with correct case and punctuation, for example: ```rst Fixed issue with non-ascii contents in doctest text files -- by :user:`contributor-gh-handle`. ``` Co-authored-by: Alexey Stavrov <[email protected]>
1 parent 928e6d7 commit e9f3f03

File tree

4 files changed

+61
-3
lines changed

4 files changed

+61
-3
lines changed

CHANGES/10529.bugfix.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed an issue where dns queries were delayed indefinitely when an exception occurred in a ``trace.send_dns_cache_miss``
2+
-- by :user:`logioniz`.

CONTRIBUTORS.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Alexandru Mihai
3131
Alexey Firsov
3232
Alexey Nikitin
3333
Alexey Popravka
34+
Alexey Stavrov
3435
Alexey Stepanov
3536
Amin Etesamian
3637
Amit Tulshyan

aiohttp/connector.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,11 +1015,11 @@ async def _resolve_host_with_throttle(
10151015
This method must be run in a task and shielded from cancellation
10161016
to avoid cancelling the underlying lookup.
10171017
"""
1018-
if traces:
1019-
for trace in traces:
1020-
await trace.send_dns_cache_miss(host)
10211018
try:
10221019
if traces:
1020+
for trace in traces:
1021+
await trace.send_dns_cache_miss(host)
1022+
10231023
for trace in traces:
10241024
await trace.send_dns_resolvehost_start(host)
10251025

tests/test_connector.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3497,6 +3497,61 @@ async def send_dns_cache_hit(self, *args: object, **kwargs: object) -> None:
34973497
await connector.close()
34983498

34993499

3500+
async def test_connector_resolve_in_case_of_trace_cache_miss_exception(
3501+
loop: asyncio.AbstractEventLoop,
3502+
) -> None:
3503+
token: ResolveResult = {
3504+
"hostname": "localhost",
3505+
"host": "127.0.0.1",
3506+
"port": 80,
3507+
"family": socket.AF_INET,
3508+
"proto": 0,
3509+
"flags": socket.AI_NUMERICHOST,
3510+
}
3511+
3512+
request_count = 0
3513+
3514+
class DummyTracer(Trace):
3515+
def __init__(self) -> None:
3516+
"""Dummy"""
3517+
3518+
async def send_dns_cache_hit(self, *args: object, **kwargs: object) -> None:
3519+
"""Dummy send_dns_cache_hit"""
3520+
3521+
async def send_dns_resolvehost_start(
3522+
self, *args: object, **kwargs: object
3523+
) -> None:
3524+
"""Dummy send_dns_resolvehost_start"""
3525+
3526+
async def send_dns_resolvehost_end(
3527+
self, *args: object, **kwargs: object
3528+
) -> None:
3529+
"""Dummy send_dns_resolvehost_end"""
3530+
3531+
async def send_dns_cache_miss(self, *args: object, **kwargs: object) -> None:
3532+
nonlocal request_count
3533+
request_count += 1
3534+
if request_count <= 1:
3535+
raise Exception("first attempt")
3536+
3537+
async def resolve_response() -> List[ResolveResult]:
3538+
await asyncio.sleep(0)
3539+
return [token]
3540+
3541+
with mock.patch("aiohttp.connector.DefaultResolver") as m_resolver:
3542+
m_resolver().resolve.return_value = resolve_response()
3543+
3544+
connector = TCPConnector()
3545+
traces = [DummyTracer()]
3546+
3547+
with pytest.raises(Exception):
3548+
await connector._resolve_host("", 0, traces)
3549+
3550+
await connector._resolve_host("", 0, traces) == [token]
3551+
3552+
await connector.close()
3553+
3554+
35003555
async def test_connector_does_not_remove_needed_waiters(
35013556
loop: asyncio.AbstractEventLoop, key: ConnectionKey
35023557
) -> None:

0 commit comments

Comments
 (0)