Skip to content

Commit 2e033e1

Browse files
committed
fix(smithy-http): auto-close aiohttp session to avoid unclosed warnings
1 parent cf555fe commit 2e033e1

1 file changed

Lines changed: 31 additions & 9 deletions

File tree

  • packages/smithy-http/src/smithy_http/aio

packages/smithy-http/src/smithy_http/aio/aiohttp.py

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
# SPDX-License-Identifier: Apache-2.0
3-
from copy import copy, deepcopy
3+
import weakref
4+
from copy import deepcopy
45
from itertools import chain
56
from typing import TYPE_CHECKING, Any
67
from urllib.parse import parse_qs
@@ -65,13 +66,22 @@ def __init__(
6566
"""
6667
_assert_aiohttp()
6768
self._config = client_config or AIOHTTPClientConfig()
68-
# Disable transparent response decompression and advertise
69-
# 'identity' to request uncompressed responses.
70-
# TODO: add a functional test once the test client framework exists
71-
self._session = _session or aiohttp.ClientSession(
72-
auto_decompress=False,
73-
headers={"Accept-Encoding": "identity"},
74-
)
69+
if _session is not None:
70+
self._session = _session
71+
else:
72+
# Disable transparent response decompression and advertise
73+
# 'identity' to request uncompressed responses.
74+
# TODO: add a functional test once the test client framework exists
75+
self._session = aiohttp.ClientSession(
76+
auto_decompress=False,
77+
headers={"Accept-Encoding": "identity"},
78+
)
79+
# Close the connector on GC/interpreter exit so aiohttp doesn't
80+
# emit "Unclosed client session"/"Unclosed connector" warnings
81+
# when the client is never closed explicitly.
82+
self._finalizer = weakref.finalize(
83+
self, self._close_session, self._session
84+
)
7585

7686
async def send(
7787
self,
@@ -143,5 +153,17 @@ async def _marshal_response(
143153
def __deepcopy__(self, memo: Any) -> "AIOHTTPClient":
144154
return AIOHTTPClient(
145155
client_config=deepcopy(self._config),
146-
_session=copy(self._session),
156+
_session=self._session,
147157
)
158+
159+
@staticmethod
160+
def _close_session(session: "aiohttp.ClientSession") -> None:
161+
"""Synchronously close a session's connector.
162+
163+
Runs from the :py:class:`weakref.finalize` hook, where there may be no
164+
running event loop, so we close the connector directly instead of
165+
awaiting ``session.close()``.
166+
"""
167+
connector = session.connector
168+
if connector is not None and not connector.closed:
169+
connector._close() # type: ignore[attr-defined]

0 commit comments

Comments
 (0)