Skip to content

WIP async session cache #2246

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions newsfragments/2016.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added session caching to the AsyncHTTPProvider
3 changes: 3 additions & 0 deletions pyvenv.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
home = /usr/bin
include-system-site-packages = false
version = 3.8.10
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added share/python-wheels/idna-2.8-py2.py3-none-any.whl
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
21 changes: 21 additions & 0 deletions tests/core/utilities/test_request.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import pytest

from aiohttp import (
ClientSession,
ClientTimeout,
)
from requests import (
Session,
adapters,
Expand Down Expand Up @@ -80,3 +86,18 @@ def test_precached_session(mocker):
assert isinstance(adapter, HTTPAdapter)
assert adapter._pool_connections == 100
assert adapter._pool_maxsize == 100


@pytest.mark.asyncio
async def test_async_precached_session(mocker):
mocker.patch("aiohttp.ClientSession.post")

session = ClientSession(raise_for_status=True)
request.cache_async_session(URI, session)
assert len(request._async_session_cache) == 1

await request.async_make_post_request(URI, b'request', ClientTimeout(60))
assert len(request._async_session_cache) == 1

await request.async_make_post_request("{0}/test".format(URI), b'request')
assert len(request._async_session_cache) == 2
30 changes: 24 additions & 6 deletions web3/_utils/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,21 @@ def cache_session(endpoint_uri: URI, session: requests.Session) -> None:
_session_cache[cache_key] = session


def cache_async_session(endpoint_uri: URI, session: ClientSession) -> None:
cache_key = generate_cache_key(endpoint_uri)
_async_session_cache[cache_key] = session


def _remove_session(key: str, session: requests.Session) -> None:
session.close()


def _remove_async_session(key: str, session: ClientSession) -> None:
session.close()


_session_cache = lru.LRU(8, callback=_remove_session)
_async_session_cache = lru.LRU(8, callback=_remove_async_session)


def _get_session(endpoint_uri: URI) -> requests.Session:
Expand All @@ -41,6 +51,13 @@ def _get_session(endpoint_uri: URI) -> requests.Session:
return _session_cache[cache_key]


def _get_async_session(endpoint_uri: URI) -> ClientSession:
cache_key = generate_cache_key(endpoint_uri)
if cache_key not in _async_session_cache:
_async_session_cache[cache_key] = ClientSession(raise_for_status=True)
return _async_session_cache[cache_key]


def make_post_request(endpoint_uri: URI, data: bytes, *args: Any, **kwargs: Any) -> bytes:
kwargs.setdefault('timeout', 10)
session = _get_session(endpoint_uri)
Expand All @@ -55,9 +72,10 @@ async def async_make_post_request(
endpoint_uri: URI, data: bytes, *args: Any, **kwargs: Any
) -> bytes:
kwargs.setdefault('timeout', ClientTimeout(10))
async with ClientSession(raise_for_status=True) as session:
async with session.post(endpoint_uri,
data=data,
*args,
**kwargs) as response:
return await response.read()
# https://github.com/ethereum/go-ethereum/issues/17069
session = _get_async_session(endpoint_uri)
async with session.post(endpoint_uri,
data=data,
*args,
**kwargs) as response:
return await response.read()
7 changes: 6 additions & 1 deletion web3/providers/async_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
)
from web3._utils.request import (
async_make_post_request,
cache_async_session,
get_default_http_endpoint,
)
from web3.types import (
Expand All @@ -39,7 +40,8 @@ class AsyncHTTPProvider(AsyncJSONBaseProvider):

def __init__(
self, endpoint_uri: Optional[Union[URI, str]] = None,
request_kwargs: Optional[Any] = None
request_kwargs: Optional[Any] = None,
session: Optional[Any] = None
) -> None:
if endpoint_uri is None:
self.endpoint_uri = get_default_http_endpoint()
Expand All @@ -48,6 +50,9 @@ def __init__(

self._request_kwargs = request_kwargs or {}

if session is not None:
cache_async_session(self.endpoint_uri, session)

super().__init__()

def __str__(self) -> str:
Expand Down