Closed senpos closed 3 years ago
Woah, that's umm, weird.
Hi @florimondmanca!
It works fine with requests
.
So, it's quite interesting.
I ran your script, and at first it worked fine. Now if I run it again, it fails consistently. If I turn on debug logging I can see it's making some of the requests (generally 7), doesn't show the output, then fails.
If I add a print("getting result")
just before the call to future.result()
, we can see it's hanging on it, and then we start to see requests terminating, then a crash before the future returns.
$ HTTPX_LOG_LEVEL=debug python debug/bug.py
getting result
DEBUG [2020-11-20 09:30:08] httpx._client - HTTP Request: POST https://httpbin.org/post "HTTP/1.1 200 OK"
DEBUG [2020-11-20 09:30:08] httpx._client - HTTP Request: POST https://httpbin.org/post "HTTP/1.1 200 OK"
DEBUG [2020-11-20 09:30:08] httpx._client - HTTP Request: POST https://httpbin.org/post "HTTP/1.1 200 OK"
DEBUG [2020-11-20 09:30:08] httpx._client - HTTP Request: POST https://httpbin.org/post "HTTP/1.1 200 OK"
DEBUG [2020-11-20 09:30:09] httpx._client - HTTP Request: POST https://httpbin.org/post "HTTP/1.1 200 OK"
DEBUG [2020-11-20 09:30:09] httpx._client - HTTP Request: POST https://httpbin.org/post "HTTP/1.1 200 OK"
DEBUG [2020-11-20 09:30:09] httpx._client - HTTP Request: POST https://httpbin.org/post "HTTP/1.1 200 OK"
DEBUG [2020-11-20 09:30:09] httpx._client - HTTP Request: POST https://httpbin.org/post "HTTP/1.1 200 OK"
DEBUG [2020-11-20 09:30:09] httpx._client - HTTP Request: POST https://httpbin.org/post "HTTP/1.1 200 OK"
Traceback (most recent call last):
File "/Users/florimond/Developer/python-projects/httpx/debug/bug.py", line 30, in <module>
main()
File "/Users/florimond/Developer/python-projects/httpx/debug/bug.py", line 25, in main
response = future.result()
File "/Users/florimond/.pyenv/versions/3.9.0/lib/python3.9/concurrent/futures/_base.py", line 433, in result
return self.__get_result()
File "/Users/florimond/.pyenv/versions/3.9.0/lib/python3.9/concurrent/futures/_base.py", line 389, in __get_result
raise self._exception
File "/Users/florimond/.pyenv/versions/3.9.0/lib/python3.9/concurrent/futures/thread.py", line 52, in run
result = self.fn(*self.args, **self.kwargs)
File "/Users/florimond/Developer/python-projects/httpx/debug/bug.py", line 13, in do_post
response = client.post("post")
File "/Users/florimond/Developer/python-projects/httpx/httpx/_client.py", line 992, in post
return self.request(
File "/Users/florimond/Developer/python-projects/httpx/httpx/_client.py", line 733, in request
return self.send(
File "/Users/florimond/Developer/python-projects/httpx/httpx/_client.py", line 767, in send
response = self._send_handling_auth(
File "/Users/florimond/Developer/python-projects/httpx/httpx/_client.py", line 805, in _send_handling_auth
response = self._send_handling_redirects(
File "/Users/florimond/Developer/python-projects/httpx/httpx/_client.py", line 837, in _send_handling_redirects
response = self._send_single_request(request, timeout)
File "/Users/florimond/Developer/python-projects/httpx/httpx/_client.py", line 861, in _send_single_request
(status_code, headers, stream, ext) = transport.request(
File "/Users/florimond/Developer/python-projects/httpx/venv/lib/python3.9/site-packages/httpcore/_sync/connection_pool.py", line 200, in request
response = connection.request(
File "/Users/florimond/Developer/python-projects/httpx/venv/lib/python3.9/site-packages/httpcore/_sync/connection.py", line 88, in request
self._create_connection(self.socket)
File "/Users/florimond/Developer/python-projects/httpx/venv/lib/python3.9/site-packages/httpcore/_sync/connection.py", line 136, in _create_connection
from .http11 import SyncHTTP11Connection
ImportError: cannot import name 'SyncHTTP11Connection' from partially initialized module 'httpcore._sync.http11' (most likely due to a circular import) (/Users/florimond/Developer/python-projects/httpx/venv/lib/python3.9/site-packages/httpcore/_sync/http11.py)
Crucially I've tested on 3.8, and I'm not able to reproduce there (even if on the same versions of HTTPX / HTTPCore). So I'm tempted to mark this as a 3.9 bug for now, though it may also be that something changed in 3.9 that revealed a problem we might have with thread-safe execution.
Ah, also a funny bit of info: this only reproduces on http11
, not http2
. Eg Client(..., http2=True)
makes the bug go away. 🤔
This bug likely comes from: https://bugs.python.org/issue35943 - Python 3.9 changed a bug which allowed imports to return partially initialized module.
This discussion ticket relates similar behavior seen with multiprocessing
: https://discuss.python.org/t/differences-between-3-8-and-3-9-in-importing-module/5520/2
This discussion^ mentions that "multiprocessing has a lot of local imports, so multiprocessing is not thread-safe". So… That local from .http11 import SyncHTTP11Connection
import might be the culprit — I didn't know it was a source of lack of thread-safety.
Yup — moving the local import of SyncHTTP11Connection
to a global one (which is fine — we don't need a local import there, since h11
is always installed) fixes it on my side.
Checklist
master
.Describe the bug
When using
httpx
withThreadPoolExecutor
onPython 3.9
I get an exception about the import error / circular import ofSyncHTTP11Connection
.I can't reproduce it on
Python 3.8
.To reproduce
With
_MAX_WORKERS=4
I get the error, but sometimes, when I change its value it works fine. Sometimes.Expected behavior
It should not throw an exception regarding circular imports when using ThreadPoolExecutor. :-)
Actual behavior
Well, it throws it. :D
Debugging material
Traceback with HTTPX_LOG_LEVEL=trace
```bash $ HTTPX_LOG_LEVEL=trace python main.py TRACE [2020-11-19 18:15:10] httpx._config - load_ssl_context verify=True cert=None trust_env=True http2=False TRACE [2020-11-19 18:15:10] httpx._config - load_verify_locations cafile=/tmp/httpx-threadpool-demo/venv/lib/python3.9/site-packages/certifi/cacert.pem TRACE [2020-11-19 18:15:10] httpcore._sync.connection_pool - get_connection_from_pool=(b'https', b'httpbin.org', 443) TRACE [2020-11-19 18:15:10] httpcore._sync.connection_pool - created connection=It looks like it is actually doing requests, but fails afterwards?
Environment
Ubuntu 20.04 on WSL2 on Windows 10
3.9.0
0.16.1
Additional context
I get the same error on the Windows version of Python 3.9 too.