-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Add SIGTERM handling in web.run_app #1946
Conversation
The testing is a bit complicated so I only tested using the script given in the original issue. |
Codecov Report
@@ Coverage Diff @@
## master #1946 +/- ##
==========================================
- Coverage 97.08% 97.07% -0.01%
==========================================
Files 37 37
Lines 7613 7622 +9
Branches 1329 1330 +1
==========================================
+ Hits 7391 7399 +8
Misses 100 100
- Partials 122 123 +1
Continue to review full report at Codecov.
|
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.
The test is still required.
I could suggest the following:
- Create a script in temp folder which creates an application and registers
on_cleanup
signal.
The signal code should do something visible to outer system like file creation. - In test code create a subprocess to execute the script.
- Send SIGTERM to it
- Wait for requested file existence.
- Delete a script and tmp file on test cleanup
aiohttp/web.py
Outdated
@@ -414,12 +423,15 @@ def run_app(app, *, host=None, port=None, path=None, sock=None, | |||
asyncio.gather(*server_creations, loop=loop) | |||
) | |||
|
|||
if handle_signals: | |||
signal.signal(signal.SIGTERM, sigterm_handler) |
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.
https://docs.python.org/3/library/asyncio-eventloop.html#unix-signals should be used for signal registration.
Also signal subscription should be skipped on Windows
def run_app(app, *, host=None, port=None, path=None, sock=None, | ||
shutdown_timeout=60.0, ssl_context=None, | ||
print=print, backlog=128, access_log_format=None, | ||
access_log=access_logger, loop=None): | ||
access_log=access_logger, handle_signals=True, loop=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.
maybe handle_sigterm
is better name?
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.
Yes actually I was thinking that you may want actually that run_app handles all the signals or none. For the user it's not really about handling SIGTERM in particular, it's more about handling the signals (INT and TERM) or not. It's unfortunate somehow that Python handles SIGINT for you by default.
I just realize now that maybe we should also handle SIGINT using https://docs.python.org/3/library/asyncio-eventloop.html#unix-signals but I'm not sure at all about it, what do you think?
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.
SIGINT is handled out of the box, why should we care about it?
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 actually answered later in the PR comments. It's not really "out of the box" for the event loop, it's out of the box for default synchronous usage of Python.
|
Could you use asyncio api for subprocesses in test instead of |
@asvetlov Yes that's what I wanted in the beginning but the test method is not asynchronous. There is no point and it would make thing unreadable. |
@asvetlov I mean: The test function is synchronous so I suppose the tests are run synchronously. The thing I'm testing spawns a process, wait for it and assert. There is only one thing done at a time. If I want to make it asynchronous it means I will have to move the test to a coroutine and the test itself will do a There is no point of doing so because the event loop will be busy with only one task. And the perk of using So unless you know how to make the tests run asynchronously in parallel like mocha.parallel, there is no real advantage to this. async def real_test():
proc = await asyncio.create_subprocess....
async for line in proc.stdout:
....
proc.terminate()
retcode = await proc.wait()
assert ...
def test_sigterm(loop):
loop.run_until_complete(real_test()) |
@asvetlov I just checked the code of asyncio and I believe we should also manage the SIGINT the same way. The reason is simply that if not managed, Python has this default behavior to raise KeyboardInterrupt. But apparently they made This is from asyncio: def add_signal_handler(self, sig, callback, *args):
(...)
handle = events.Handle(callback, args, self)
self._signal_handlers[sig] = handle
try:
# Register a dummy signal handler to ask Python to write the signal
# number in the wakup file descriptor. _process_self_data() will
# read signal numbers from this file descriptor to handle signals.
signal.signal(sig, _sighandler_noop)
# Set SA_RESTART to limit EINTR occurrences.
signal.siginterrupt(sig, False)
(...) This is the doc for siginterrupt:
The other reason that makes me think we should handle it is that they are managing the signals with the event loop itself. I'm not sure what are the consequences because KeyboardInterrupt and the |
a24f2a1
to
91f5e66
Compare
@asvetlov I'm going to give up the signal testing on Windows if you don't mind... Apparently the console ask to confirm when you send a signal CTRL_BREAK_EVENT or CTRL_C_EVENT:
By the way, you may have notice that your Windows CI (appveyor) is a bit stuck? This is because each build wait 1 hour before being killed. Since there are 6 builds every time, it's waiting 6 hours. I didn't realize fast enough and I'm afraid I'm blocking your CI for 7 hours now and there are still 5 hours to go. Hum.... sorry? |
Oooh. If Windows hangs with user prompt -- please don't run test on it. I'm fine with your proposal. |
@asvetlov ok finally done :) Are you sure about the subprocess? Did I convince you? |
Thanks |
What do these changes do?
Makes
web.run_app()
handle SIGTERM by default to gracefully exit the application.Are there changes in behavior for the user?
The application run with
web.run_app()
will override any existing SIGTERM handler in the current process.Related issue number
#1932
Checklist
CONTRIBUTORS.txt
CHANGES.rst
#issue_number
format at the end of changelog message. Use Pull Request number if there are no issues for PR or PR covers the issue only partially.