-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Conversation
Upgraded pytest-mock
@kclowes do you have any feedback on this PR. Am I on the right track? |
This looks good @dbfreem! Thanks for looking into this and for all the PRs! On first glance, this is about what I would expect in regards to caching the session. I'd probably drop the If you pull in the latest master, some of those integration test failures should be less flaky. |
I removed the the pytest-mock upgrade and pulled the latest from master. I love python and enjoy the web3 concept in general so just thought I would try to get involved. |
…eem/web3.py into feature/async_session_cache
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this PR @dbfreem and for responding to so many of our issues!
There is an existing bug with the current sync implementation where the LRU cache isn't thread safe (see here: #1847), and I wonder what it would take to make this async version thread safe right off the bat. It may be as easy as pulling in the threading library and using threading.Lock
as a context manager, but I'm not sure. I am also fine putting that in a different PR (that either you or someone else can tackle, no pressure).
Other than that, I just had a few nitpicks! Thanks again!
tests/core/utilities/test_request.py
Outdated
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# Make sure a request with a different URI addes another cached session | |
# Make sure a request with a different URI adds another cached session |
tests/core/utilities/test_request.py
Outdated
assert len(request._async_session_cache) == 1 | ||
|
||
# Make sure a request with a different URI addes another cached session | ||
request.cache_async_session("{0}/test".format(URI), session) |
There was a problem hiding this comment.
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:
request.cache_async_session("{0}/test".format(URI), session) | |
request.cache_async_session(f"{URI}/test", session) |
I was actually wondering if issue #2253 was a thread safe issue on the standard http side. I will take a look at your comments and thread safety. |
So I haven't done a lot of threading before but based on what I say in cache.py plus reading up on python.org about threading lock I think this will work. Unfortunately, this is really hard to test with a unit test. If you agree with this threading approach I can make the same change in another PR for #1847 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good @dbfreem. Thank you for the work! I've been looking a little bit at how to test the threading, so I'll let you know if I see anything promising.
working on the test for this and did find a bug in the logic so working on fixing that. |
This still needs a little work so don't merge this. I will take a look this weekend. |
So here is where I am with this. After I started writing a test to test the thread safety stuff I realized that
One other side effect that came of this is that I am no longer able to reproduce the threading issue that was there before I changed to I do see that lru-dict is used in Thoughts?? I can go another route if you all do not agree with the |
Ok, final answer here. Once, I built the unit test for the All these changes started from the fact that the Also, on the new @kclowes can you review this |
Thanks @dbfreem! One of us will take a look this week! |
@dbfreem haven't forgotten this one. Will take a look! Thank you! |
Thanks @kclowes. I know this turned into a big PR, sorry about that. It kind of spiraled once I realized that the session close for the aiohttp was an async method and it wasn't actually being closed the way I had it at first. |
Co-authored-by: Paul Robinson <[email protected]>
Co-authored-by: Paul Robinson <[email protected]>
@pacrob I committed your suggestions. Thanks |
ethereum#2254) * Added caching to the async session in request.py and AsyncHTTPProvider
#2254) (#2363) * Added caching to the async session in request.py and AsyncHTTPProvider Co-authored-by: AlwaysData <[email protected]>
Thanks for adding this, @dbfreem ! I added the _ myself just to cut cycle time. Otherwise, awesome work as usual 👍 |
No worries about the _ @pacrob and you are welcome. |
Just a note that I'm having trouble utilizing this. I typically run web3 within a pycord (fork of discord.py) bot, which until this change has been working without issue. I applied |
@DefiDebauchery thanks for the report. Any chance you can open up a new issue with a minimum reproducible example? |
What was wrong?
When I was researching the timeouts in the benchmark test I noticed the session is not cached in the request.py for Async aiohttp request. Mainly when I read this issue on the geth repo about multiple http sessions I realized this might be an issue.
Also, the aiohttp library recommends reusing sessions
I feel like as a follow up to this PR the request.py should be broken apart into two classes. One for Async and one for standard HTTP. This would better organize the code and make it more testable.
How was it fixed?
For the test I started with what was in the
test_precached_session
and modified it for the async request. I also used thepytest.mark.asyncio
that I found else where in the project for async testing.I also started with the code that was used in request.py and HTTPProvider for the caching and modified it for async.
I upgraded pytest-mock trying to get the Async Mocking to work for the aiohttp session with no success in python 3.6. Since I couldn't get the mock working on the async
session.post
I only tested the session caching and not thepost
call on the session in request.py. Since there didn't seem to be any conflicts with the upgrade as long as it was less than 3.3.0 I left it in this PR.I did find an issue later on related to session caching in the web3.py issues list.
Related to Issue #2016
Todo: