-
-
Notifications
You must be signed in to change notification settings - Fork 31.4k
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
Spurious "Exception in callback None()" after upgrading to 3.12 #115514
Comments
3.12.2 was released a week ago. Try that? Perhaps you should ask on https://discuss.python.org/c/users/7 as it seems at least half likely that the bug is in aiohttp or your code as in asyncio. |
There is nothing I can do for you unless you debug this further, sorry. Above suggestions are right. |
Closing because of no further comments and reproducer. |
Hello, sorry for very late response - unfortunately, this is very hard to reproduce reliably because it only happens in high-traffic situations with complex, closed-source apps. I now think that this is caused by 3.12 switch to optional The code in cpython/Lib/asyncio/selector_events.py Lines 857 to 865 in 7303f06
close is called while the buffer is not empty, we should keep writing - but the PR breaks that, preventing the buffer to be written immeaditelly after close is called.
I think the reference to Now, I have no idea how is it possible that other people are not running into this. Perhaps it is caused by our internal company network environment or something, but the behavior here clearly changed in 3.12. I will prepare a PR with fix and a test, can you please re-open this issue? |
I have no opinion on this, because how do I know that the bug isn’t in your code? But I will reopen the issue — clearly we need to consider that it is on our side. |
I spent a few hours trying to prepare some reasonable reproduction code, but it does not seem possible - the corner case depends on particular network state. I did try at least outlining the state in the test in the PR though. But I think it boils down to a simple question - should |
Yes, |
The However, there is pretty complex interaction with SSLProtocol, where writes are scheduled just before its shutdown, and eventually the one originating from I've dug even more, and it looks like the interaction is this:
Indeed it does not seem to make sense to keep writing SSLProtocol buffer out after it has been shutdown, so perhaps more sensible fix is this in SSLProtocol: diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py
index 74c5f0d5ca0..1c05bb3e47a 100644
--- a/Lib/asyncio/sslproto.py
+++ b/Lib/asyncio/sslproto.py
@@ -716,6 +716,9 @@ def _do_write(self):
self._process_outgoing()
def _process_outgoing(self):
+ if self._transport.is_closing():
+ return
+
if not self._ssl_writing_paused:
data = self._outgoing.read()
if len(data): EDIT: except there is a test that checks exactly this, it verifies that whole SSLProtocol buffer is sent after shutdown: cpython/Lib/test/test_asyncio/test_ssl.py Lines 1310 to 1432 in 8a433b6
For this test to pass, I think
I think the difference is that with [1]:
```
File "/usr/local/lib/python3.12/asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
File "/usr/local/lib/python3.12/asyncio/base_events.py", line 674, in run_until_complete
self.run_forever()
File "/usr/local/lib/python3.12/asyncio/base_events.py", line 641, in run_forever
self._run_once()
File "/usr/local/lib/python3.12/asyncio/base_events.py", line 1978, in _run_once
handle._run()
File "/usr/local/lib/python3.12/asyncio/events.py", line 88, in _run
self._context.run(self._callback, *self._args)
File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 970, in _read_ready
self._read_ready_cb()
File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 1002, in _read_ready__get_buffer
self._protocol.buffer_updated(nbytes)
File "/usr/local/lib/python3.12/asyncio/sslproto.py", line 442, in buffer_updated
self._do_read()
File "/usr/local/lib/python3.12/asyncio/sslproto.py", line 737, in _do_read
self._do_read__copied()
File "/usr/local/lib/python3.12/asyncio/sslproto.py", line 803, in _do_read__copied
self._start_shutdown()
File "/usr/local/lib/python3.12/asyncio/sslproto.py", line 628, in _start_shutdown
self._do_flush()
File "/usr/local/lib/python3.12/asyncio/sslproto.py", line 642, in _do_flush
self._set_state(SSLProtocolState.SHUTDOWN)
```
|
I think we have the same issue on Python 3.12.2, during heavy upload to AWS S3 by aiobotocore which use aiohttp client with SSL. We are using short live sessions and I believe S3 time to time close TCP connections to update session. I will try to find a way to test a PR from @Tasssadar |
#128037) Co-authored-by: Kumar Aditya <kumaraditya@python.org>
… asyncio(pythonGH-128037) (cherry picked from commit 4e38eea) Co-authored-by: Vojtěch Boček <vbocek@gmail.com> Co-authored-by: Kumar Aditya <kumaraditya@python.org>
… asyncio(pythonGH-128037) (cherry picked from commit 4e38eea) Co-authored-by: Vojtěch Boček <vbocek@gmail.com> Co-authored-by: Kumar Aditya <kumaraditya@python.org>
… asyncio(python#128037) Co-authored-by: Kumar Aditya <kumaraditya@python.org>
Bug report
Bug description:
Hello, after upgrading our application to 3.12.1 that uses aiohttp to download stuff via HTTPS as well as connects to some RabbitMQ servers via ssl, we get this spurious exception to stderr, dozens-hundres of them in close succession.
They happen after several minutes of running (so after dozens of ssl connections are used).
Unfortunately, I can't tell what is the culprit, the trace contains nothing other than the runtime :( I can provide more info if you give me some pointers on where to look. It looks like write-after-close, but the "writing" is done by internal asyncio mechanisms.
CPython versions tested on:
3.12
Operating systems tested on:
Linux
Linked PRs
The text was updated successfully, but these errors were encountered: