-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Implement web.Runner
context manager
#8723
base: master
Are you sure you want to change the base?
Conversation
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.
Looks like a good start. Still needs some fixes and documentation.
aiohttp/web.py
Outdated
if ( | ||
threading.current_thread() is threading.main_thread() | ||
and signal.getsignal(signal.SIGINT) is signal.default_int_handler | ||
): | ||
sigint_handler = functools.partial(self._on_sigint, main_task=task) | ||
try: | ||
signal.signal(signal.SIGINT, sigint_handler) | ||
except ValueError: | ||
# `signal.signal` may throw if `threading.main_thread` does | ||
# not support signals (e.g. embedded interpreter with signals | ||
# not registered - see gh-91880) | ||
sigint_handler = None | ||
else: | ||
sigint_handler = None |
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.
I wonder if this SIGINT code needs to be copied to run_app()...
Will have to do some more testing.
tests/test_runner.py
Outdated
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.
We'll also want some tests in test_run_app.py to verify the .run_app() method separately.
e.g. Maybe test that running a simple task followed by .run_app() works (and happens in the same loop).
@bdraco Does this look reasonable overall? |
Also, looking at the implementation, the .run_app() method only uses ._lazy_init() and ._loop from the class. So, I'm wondering if we should just ignore the comment about the class being final and subclass it anyway. Then just rely on decent tests to ensure we maintain compatibility. |
Traveling today for the next 23 hours. Will take a look when I get to my destination |
Looks like I'll be able to look today after all. Flight isn't happening due to engine issues so I'll be able to look once I get rebooked and back home. |
It looks reasonable to me. I want to subclass it instead of copying all the code, as keeping it in sync imposes some maintenance burden. Unfortunately, upstream explicitly says not to do that. We should add some comments about periodically checking upstream for bug fixes if we don't want to ignore that and do it anyways since we will have an out-of-sync copy as soon as anything changes. |
Yeah, I think we should just subclass it, there's just too much code otherwise with tests duplicated etc. We only depend on lazy_init and the loop attribute from the class, so I think risk of breakage is low. @DavidRomanovizc Would you be alright changing it to a subclass and removing the copied tests?
Then in web.run_app() also do a version check and use the new Runner code in 3.11+ or the old implementation otherwise (we'll then remove the old version when we drop support for 3.10). |
Co-authored-by: Sam Bull <[email protected]>
Co-authored-by: Sam Bull <[email protected]>
Co-authored-by: Sam Bull <[email protected]>
Sorry for the long inactivity. Decided to rename |
CodSpeed Performance ReportMerging #8723 will not alter performanceComparing Summary
|
class WebRunner(asyncio.Runner): # type: ignore | ||
"""A context manager that controls event loop life cycle""" | ||
|
||
def __init__( |
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.
Still a lot of copied code here. As far as I can tell, only the run_app() method needs to be defined here. init/close/_lazy_init can all be removed and just use the parent methods.
if not access_log.hasHandlers(): | ||
access_log.addHandler(logging.StreamHandler()) | ||
|
||
main_task = self._loop.create_task( |
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.
Should probably add the context parameter for compatibility:
https://github.com/python/cpython/blob/dc76a4ad3c46af3fb70361be10b8a791cd126931/Lib/asyncio/runners.py#L106-L109
INITIALIZED = "initialized" | ||
CLOSED = "closed" | ||
|
||
class WebRunner(asyncio.Runner): # type: ignore |
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.
We should probably get a new test that uses WebRunner directly too. Can probably just copy and modify one of the run_app() tests. The new test could also use WebRunner.run() to verify that the task and the app are run in the same loop.
@Dreamsorcerer, I thought, why don't we replace inheritance with composition? We will still be able to use the functionality of like that: class WebRunner:
def __init__(
self,
*,
debug: Optional[bool] = None,
loop_factory: Optional[Callable[[], asyncio.AbstractEventLoop]] = None,
):
self.debug = debug
self.loop_factory = loop_factory
self._runner = asyncio.Runner(debug=debug, loop_factory=loop_factory)
... |
Co-authored-by: Sam Bull <[email protected]>
We need to call _lazy_init(), right? So, we can't just rely on the public interface.. |
What do these changes do?
These changes introduce the
web.Runner
context manager, based onasyncio.Runner
. Addedweb.Runner.run_app
method and refactored existingweb.run_app
to useweb.Runner.run_app
for running server. This feature preserves the backward compatibilityAre there changes in behavior for the user?
I think there aren't changes in behavior for users who will continue to use
web.run_app
as before; it remains fully compatible with existing code but users now have the option to useweb.Runner.run_app
Is it a substantial burden for the maintainers to support this?
Supporting this change shouldn't be a substantial burden for maintainers because
web.Runner
builds on theasyncio.Runner
with minor additionsRelated to Issue: #8028
Checklist
CONTRIBUTORS.txt
CHANGES/
folder