Skip to content
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

Added caching to the async session in request.py and AsyncHTTPProvider #2254

Merged
merged 27 commits into from
Feb 24, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
38f7e84
Added caching to the async session in request.py and AsyncHTTPProvider
dbfreem Dec 15, 2021
92ceac1
reverted pytest-mock upgrade
dbfreem Dec 16, 2021
ee778ae
Merge branch 'ethereum:master' into feature/async_session_cache
dbfreem Dec 16, 2021
229533f
removed pytest-mock upgrade from news
dbfreem Dec 16, 2021
801638b
Merge branch 'feature/async_session_cache' of https://github.com/dbfr…
dbfreem Dec 16, 2021
3cff06f
made small suggested changes
dbfreem Dec 18, 2021
00f2c67
typo
dbfreem Dec 18, 2021
ff12510
added thread lock to the async session cache
dbfreem Dec 18, 2021
b9dcffb
Merge branch 'ethereum:master' into feature/async_session_cache
dbfreem Jan 12, 2022
e7bbec5
removed lock around close since it was causing deadlocks
dbfreem Jan 14, 2022
097fa1b
accidently commited test that I was working on
dbfreem Jan 14, 2022
3d9e77b
Added SessionCache class
dbfreem Jan 16, 2022
eae163d
rearranged the cache code
dbfreem Jan 16, 2022
65b12f2
added one more test on new SessionCache
dbfreem Jan 16, 2022
f713776
lint
dbfreem Jan 16, 2022
9656ae8
Had the wrong import not sure how that worked locally
dbfreem Jan 16, 2022
88ee5ac
updated docs
dbfreem Jan 16, 2022
1720df3
fixed updating of existing cache items
dbfreem Jan 16, 2022
e307c8b
lint problem again
dbfreem Jan 16, 2022
4289e64
slight changes to docs
dbfreem Jan 16, 2022
8bdcbcd
Moved caching of session in AsynHTTPProvider to a method since it is …
dbfreem Jan 16, 2022
503146d
Merge branch 'ethereum:master' into feature/async_session_cache
dbfreem Jan 26, 2022
92a2b84
Merge branch 'ethereum:master' into feature/async_session_cache
dbfreem Feb 1, 2022
e1ff8fe
Merge branch 'ethereum:master' into feature/async_session_cache
dbfreem Feb 8, 2022
40ca5f9
Update docs/providers.rst
dbfreem Feb 24, 2022
cf29678
Update web3/_utils/request.py
dbfreem Feb 24, 2022
2d3a275
add _ for confusion reduction
Feb 24, 2022
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
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,8 @@
import pytest

from aiohttp import (
ClientSession,
)
from requests import (
Session,
adapters,
Expand Down Expand Up @@ -80,3 +85,19 @@ 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):
# Add a session
session = ClientSession()
request.cache_async_session(URI, session)
assert len(request._async_session_cache) == 1

# Make sure the session isn't duplicated
request.cache_async_session(URI, session)
assert len(request._async_session_cache) == 1

# Make sure a request with a different URI addes another cached session
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Make sure a request with a different URI addes another cached session
# Make sure a request with a different URI adds another cached session

request.cache_async_session("{0}/test".format(URI), session)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick - we tend to prefer using f-strings:

Suggested change
request.cache_async_session("{0}/test".format(URI), session)
request.cache_async_session(f"{URI}/test", session)

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