Repository navigation
An open stream object is being garbage collected; call "stream.close()" explicitly #714
Copy link
Copy link
Closed
Labels
concurrency/asyncioIssues related to concurrency (asyncio-only)Issues related to concurrency (asyncio-only)externalRoot cause pending resolution in an external dependencyRoot cause pending resolution in an external dependency
Description
I can trigger an ERROR: An open stream object is being garbage collected; call "stream.close()" explicitly. on demand in my test suite
the trace output is just below:
DEBUG:conftest:Starting ngrok tunnel for port 5002
-------------------------------- live log setup --------------------------------
DEBUG conftest:conftest.py:46 Starting ngrok tunnel for port 5002
DEBUG:asyncio:Using selector: EpollSelector
DEBUG asyncio:selector_events.py:54 Using selector: EpollSelector
INFO: Started server process [3098472]
INFO: Uvicorn running on http://127.0.0.1:5002 (Press CTRL+C to quit)
INFO: Waiting for application startup.
INFO: Connected to database postgresql://postgres:********@localhost:5438/rss2inbox_test
INFO: Application startup complete.
TRACE [2020-01-02 12:02:01] httpx.dispatch.connection_pool - acquire_connection origin=Origin(scheme='https' host='websub.rocks' port=443)
TRACE: acquire_connection origin=Origin(scheme='https' host='websub.rocks' port=443)
TRACE [2020-01-02 12:02:01] httpx.dispatch.connection_pool - new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE: new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE [2020-01-02 12:02:01] httpx.config - load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE: load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE [2020-01-02 12:02:01] httpx.config - load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE: load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE [2020-01-02 12:02:01] httpx.dispatch.connection - start_connect tcp host='websub.rocks' port=443 timeout=Timeout(timeout=5.0)
TRACE: start_connect tcp host='websub.rocks' port=443 timeout=Timeout(timeout=5.0)
TRACE [2020-01-02 12:02:01] httpx.dispatch.connection - connected http_version='HTTP/1.1'
TRACE: connected http_version='HTTP/1.1'
TRACE [2020-01-02 12:02:01] httpx.dispatch.http11 - send_headers method='GET' target='/subscriber/100' headers=Headers({'host': 'websub.rocks', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive'})
TRACE: send_headers method='GET' target='/subscriber/100' headers=Headers({'host': 'websub.rocks', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive'})
TRACE [2020-01-02 12:02:01] httpx.dispatch.http11 - send_data data=Data(<0 bytes>)
TRACE: send_data data=Data(<0 bytes>)
TRACE [2020-01-02 12:02:01] httpx.dispatch.http11 - receive_event event=NEED_DATA
TRACE: receive_event event=NEED_DATA
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - receive_event event=Response(status_code=200, headers=[(b'server', b'nginx/1.14.2'), (b'date', b'Thu, 02 Jan 2020 11:02:02 GMT'), (b'content-type', b'text/html; charset=UTF-8'), (b'content-length', b'4912'), (b'connection', b'keep-alive')], http_version=b'1.1', reason=b'OK')
TRACE: receive_event event=Response(status_code=200, headers=[(b'server', b'nginx/1.14.2'), (b'date', b'Thu, 02 Jan 2020 11:02:02 GMT'), (b'content-type', b'text/html; charset=UTF-8'), (b'content-length', b'4912'), (b'connection', b'keep-alive')], http_version=b'1.1', reason=b'OK')
DEBUG [2020-01-02 12:02:02] httpx.client - HTTP Request: GET https://websub.rocks/subscriber/100 "HTTP/1.1 200 OK"
DEBUG: HTTP Request: GET https://websub.rocks/subscriber/100 "HTTP/1.1 200 OK"
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - receive_event event=Data(<3932 bytes>)
TRACE: receive_event event=Data(<3932 bytes>)
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - receive_event event=NEED_DATA
TRACE: receive_event event=NEED_DATA
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - receive_event event=Data(<980 bytes>)
TRACE: receive_event event=Data(<980 bytes>)
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - receive_event event=EndOfMessage(headers=[])
TRACE: receive_event event=EndOfMessage(headers=[])
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - response_closed our_state=DONE their_state=DONE
TRACE: response_closed our_state=DONE their_state=DONE
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection_pool - release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE: release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection - close_connection
TRACE: close_connection
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - send_event event=ConnectionClosed()
TRACE: send_event event=ConnectionClosed()
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection_pool - acquire_connection origin=Origin(scheme='https' host='75d55904.ngrok.io' port=443)
TRACE: acquire_connection origin=Origin(scheme='https' host='75d55904.ngrok.io' port=443)
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection_pool - new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='75d55904.ngrok.io' port=443))
TRACE: new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='75d55904.ngrok.io' port=443))
TRACE [2020-01-02 12:02:02] httpx.config - load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE: load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE [2020-01-02 12:02:02] httpx.config - load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE: load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection - start_connect tcp host='75d55904.ngrok.io' port=443 timeout=Timeout(timeout=5.0)
TRACE: start_connect tcp host='75d55904.ngrok.io' port=443 timeout=Timeout(timeout=5.0)
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection - connected http_version='HTTP/1.1'
TRACE: connected http_version='HTTP/1.1'
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - send_headers method='GET' target='/subscribe?subscribe_to_url=https%3A%2F%2Fwebsub.rocks%2Fblog%2F100%2FWBj716u7rareKpjbfoh9' headers=Headers({'host': '75d55904.ngrok.io', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive'})
TRACE: send_headers method='GET' target='/subscribe?subscribe_to_url=https%3A%2F%2Fwebsub.rocks%2Fblog%2F100%2FWBj716u7rareKpjbfoh9' headers=Headers({'host': '75d55904.ngrok.io', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive'})
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - send_data data=Data(<0 bytes>)
TRACE: send_data data=Data(<0 bytes>)
TRACE [2020-01-02 12:02:02] httpx.dispatch.http11 - receive_event event=NEED_DATA
TRACE: receive_event event=NEED_DATA
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection_pool - acquire_connection origin=Origin(scheme='https' host='websub.rocks' port=443)
TRACE: acquire_connection origin=Origin(scheme='https' host='websub.rocks' port=443)
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection_pool - new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE: new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE [2020-01-02 12:02:02] httpx.config - load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE: load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE [2020-01-02 12:02:02] httpx.config - load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE: load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE [2020-01-02 12:02:02] httpx.dispatch.connection - start_connect tcp host='websub.rocks' port=443 timeout=Timeout(timeout=5.0)
TRACE: start_connect tcp host='websub.rocks' port=443 timeout=Timeout(timeout=5.0)
TRACE [2020-01-02 12:02:03] httpx.dispatch.connection - connected http_version='HTTP/1.1'
TRACE: connected http_version='HTTP/1.1'
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - send_headers method='GET' target='/blog/100/WBj716u7rareKpjbfoh9' headers=Headers({'host': 'websub.rocks', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive'})
TRACE: send_headers method='GET' target='/blog/100/WBj716u7rareKpjbfoh9' headers=Headers({'host': 'websub.rocks', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive'})
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - send_data data=Data(<0 bytes>)
TRACE: send_data data=Data(<0 bytes>)
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - receive_event event=NEED_DATA
TRACE: receive_event event=NEED_DATA
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - receive_event event=Response(status_code=200, headers=[(b'server', b'nginx/1.14.2'), (b'date', b'Thu, 02 Jan 2020 11:02:03 GMT'), (b'content-type', b'text/html; charset=UTF-8'), (b'content-length', b'2238'), (b'connection', b'keep-alive'), (b'link', b'<https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9>; rel="self"'), (b'link', b'<https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9/hub>; rel="hub"')], http_version=b'1.1', reason=b'OK')
TRACE: receive_event event=Response(status_code=200, headers=[(b'server', b'nginx/1.14.2'), (b'date', b'Thu, 02 Jan 2020 11:02:03 GMT'), (b'content-type', b'text/html; charset=UTF-8'), (b'content-length', b'2238'), (b'connection', b'keep-alive'), (b'link', b'<https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9>; rel="self"'), (b'link', b'<https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9/hub>; rel="hub"')], http_version=b'1.1', reason=b'OK')
DEBUG [2020-01-02 12:02:03] httpx.client - HTTP Request: GET https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9 "HTTP/1.1 200 OK"
DEBUG: HTTP Request: GET https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9 "HTTP/1.1 200 OK"
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - receive_event event=Data(<2238 bytes>)
TRACE: receive_event event=Data(<2238 bytes>)
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - receive_event event=EndOfMessage(headers=[])
TRACE: receive_event event=EndOfMessage(headers=[])
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - response_closed our_state=DONE their_state=DONE
TRACE: response_closed our_state=DONE their_state=DONE
TRACE [2020-01-02 12:02:03] httpx.dispatch.connection_pool - release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE: release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE [2020-01-02 12:02:03] httpx.dispatch.connection - close_connection
TRACE: close_connection
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - send_event event=ConnectionClosed()
TRACE: send_event event=ConnectionClosed()
DEBUG: hub_url='https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9/hub' topic_url='https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9'
ERROR: An open stream object is being garbage collected; call "stream.close()" explicitly.
TRACE [2020-01-02 12:02:03] httpx.dispatch.connection_pool - acquire_connection origin=Origin(scheme='https' host='websub.rocks' port=443)
TRACE: acquire_connection origin=Origin(scheme='https' host='websub.rocks' port=443)
TRACE [2020-01-02 12:02:03] httpx.dispatch.connection_pool - new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE: new_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE [2020-01-02 12:02:03] httpx.config - load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE: load_ssl_context verify=True cert=None trust_env=True http2=False
TRACE [2020-01-02 12:02:03] httpx.config - load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE: load_verify_locations cafile=/home/lotso/.local/share/virtualenvs/rss2inbox-IweRxOhH/lib/python3.8/site-packages/certifi/cacert.pem
TRACE [2020-01-02 12:02:03] httpx.dispatch.connection - start_connect tcp host='websub.rocks' port=443 timeout=Timeout(timeout=5.0)
TRACE: start_connect tcp host='websub.rocks' port=443 timeout=Timeout(timeout=5.0)
TRACE [2020-01-02 12:02:03] httpx.dispatch.connection - connected http_version='HTTP/1.1'
TRACE: connected http_version='HTTP/1.1'
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - send_headers method='POST' target='/blog/100/WBj716u7rareKpjbfoh9/hub' headers=Headers({'host': 'websub.rocks', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive', 'content-length': '235', 'content-type': 'application/x-www-form-urlencoded'})
TRACE: send_headers method='POST' target='/blog/100/WBj716u7rareKpjbfoh9/hub' headers=Headers({'host': 'websub.rocks', 'user-agent': 'python-httpx/0.10.0', 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive', 'content-length': '235', 'content-type': 'application/x-www-form-urlencoded'})
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - send_data data=Data(<235 bytes>)
TRACE: send_data data=Data(<235 bytes>)
TRACE [2020-01-02 12:02:03] httpx.dispatch.http11 - receive_event event=NEED_DATA
TRACE: receive_event event=NEED_DATA
INFO: 2600:3c01::f03c:91ff:fe94:80b2:0 - "GET /callbacks/6faf64d5-ab53-403e-8349-1a6889ac2ffb?hub.mode=subscribe&hub.topic=https%3A%2F%2Fwebsub.rocks%2Fblog%2F100%2FWBj716u7rareKpjbfoh9&hub.challenge=O9M7grqDIEoZTBkld6bX&hub.lease_seconds=86400 HTTP/1.1" 200 OK
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - receive_event event=Response(status_code=202, headers=[(b'server', b'nginx/1.14.2'), (b'date', b'Thu, 02 Jan 2020 11:02:04 GMT'), (b'content-type', b'text/html; charset=UTF-8'), (b'content-length', b'0'), (b'connection', b'keep-alive')], http_version=b'1.1', reason=b'Accepted')
TRACE: receive_event event=Response(status_code=202, headers=[(b'server', b'nginx/1.14.2'), (b'date', b'Thu, 02 Jan 2020 11:02:04 GMT'), (b'content-type', b'text/html; charset=UTF-8'), (b'content-length', b'0'), (b'connection', b'keep-alive')], http_version=b'1.1', reason=b'Accepted')
DEBUG [2020-01-02 12:02:04] httpx.client - HTTP Request: POST https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9/hub "HTTP/1.1 202 Accepted"
DEBUG: HTTP Request: POST https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9/hub "HTTP/1.1 202 Accepted"
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - receive_event event=EndOfMessage(headers=[])
TRACE: receive_event event=EndOfMessage(headers=[])
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - response_closed our_state=DONE their_state=DONE
TRACE: response_closed our_state=DONE their_state=DONE
TRACE [2020-01-02 12:02:04] httpx.dispatch.connection_pool - release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE: release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='websub.rocks' port=443))
TRACE [2020-01-02 12:02:04] httpx.dispatch.connection - close_connection
TRACE: close_connection
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - send_event event=ConnectionClosed()
TRACE: send_event event=ConnectionClosed()
INFO: 93.31.210.155:0 - "GET /subscribe?subscribe_to_url=https%3A%2F%2Fwebsub.rocks%2Fblog%2F100%2FWBj716u7rareKpjbfoh9 HTTP/1.1" 200 OK
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - receive_event event=Response(status_code=200, headers=[(b'date', b'Thu, 02 Jan 2020 11:02:02 GMT'), (b'server', b'uvicorn'), (b'content-length', b'38'), (b'content-type', b'application/json')], http_version=b'1.1', reason=b'OK')
TRACE: receive_event event=Response(status_code=200, headers=[(b'date', b'Thu, 02 Jan 2020 11:02:02 GMT'), (b'server', b'uvicorn'), (b'content-length', b'38'), (b'content-type', b'application/json')], http_version=b'1.1', reason=b'OK')
DEBUG [2020-01-02 12:02:04] httpx.client - HTTP Request: GET https://75d55904.ngrok.io/subscribe?subscribe_to_url=https%3A%2F%2Fwebsub.rocks%2Fblog%2F100%2FWBj716u7rareKpjbfoh9 "HTTP/1.1 200 OK"
DEBUG: HTTP Request: GET https://75d55904.ngrok.io/subscribe?subscribe_to_url=https%3A%2F%2Fwebsub.rocks%2Fblog%2F100%2FWBj716u7rareKpjbfoh9 "HTTP/1.1 200 OK"
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - receive_event event=Data(<38 bytes>)
TRACE: receive_event event=Data(<38 bytes>)
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - receive_event event=EndOfMessage(headers=[])
TRACE: receive_event event=EndOfMessage(headers=[])
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - response_closed our_state=DONE their_state=DONE
TRACE: response_closed our_state=DONE their_state=DONE
TRACE [2020-01-02 12:02:04] httpx.dispatch.connection_pool - release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='75d55904.ngrok.io' port=443))
TRACE: release_connection connection=HTTPConnection(origin=Origin(scheme='https' host='75d55904.ngrok.io' port=443))
TRACE [2020-01-02 12:02:04] httpx.dispatch.connection - close_connection
TRACE: close_connection
TRACE [2020-01-02 12:02:04] httpx.dispatch.http11 - send_event event=ConnectionClosed()
TRACE: send_event event=ConnectionClosed()
6faf64d5-ab53-403e-8349-1a6889ac2ffb
PASSED
the test that triggers it is below async def test100, I tried to copy most relevant code, I';m sorry it's that long....:
def get_url_from_page(content):
htmlcontent = html.document_fromstring(content)
link = htmlcontent.xpath("//input/@value")
return link[0]
urls_100 = [
"https://websub.rocks/subscriber/100",
"https://websub.rocks/subscriber/101",
"https://websub.rocks/subscriber/102",
"https://websub.rocks/subscriber/103",
"https://websub.rocks/subscriber/104",
]
@pytest.mark.asyncio
@pytest.mark.parametrize("websub_test_url", urls_100)
async def test100(websub_test_url, subscriber_server, ngrokurl_subscriber):
response = await httpx.get(websub_test_url)
subscribe_to_url = get_url_from_page(response.content)
url = subscriber_app.url_path_for("subscribe")
response = await httpx.get(
ngrokurl_subscriber + url, params={"subscribe_to_url": subscribe_to_url}
)
print(response.json())
assert response.status_code == 200
@pytest.fixture()
async def subscriber_server():
config = Config(app=subscriber_app, port=5002)
server = Server(config=config)
task = asyncio.ensure_future(server.serve())
try:
while not server.started:
await asyncio.sleep(0.0001)
yield server
finally:
logger.debug("END SERVER")
server.should_exit = True
await task
class NgrokTunnel:
def __init__(self, port: str):
assert find_executable(
"ngrok"
), "ngrok command must be installed, see https://ngrok.com/"
self.port = port
def start(self, ngrok_die_check_delay=0.5):
logger.debug(f"Starting ngrok tunnel for port {self.port}")
pattern = r"^.*addr=(?P<addr>http://localhost:(?P<port>\d+)) url=(?P<ngrokurl>https://(?P<ngroksubdomain>.*)\.ngrok\.io)$"
self.ngrok = subprocess.Popen(
[
"ngrok",
"http",
self.port,
"--log",
"stdout",
],
stdout=subprocess.PIPE,
bufsize=1,
universal_newlines=True,
)
found = False
ngrokurl = None
while not found:
for line in self.ngrok.stdout:
# logger.debug(line, end="")
m = re.match(pattern, line)
if m is not None:
# addr = m.group("addr")
# port = m.group("port")
ngrokurl = m.group("ngrokurl")
# ngroksubdomain = m.group("ngroksubdomain")
found = True
break
# See that we don't instantly die
time.sleep(ngrok_die_check_delay)
assert self.ngrok.poll() is None, "ngrok terminated abrutly"
return ngrokurl
def stop(self):
"""Tell ngrok to tear down the tunnel.
Stop the background tunneling process.
"""
self.ngrok.terminate()
@pytest.fixture(scope="session", autouse=True)
def ngrokurl_subscriber():
ngrok_subscriber = NgrokTunnel("5002")
url = ngrok_subscriber.start()
yield url
ngrok_subscriber.stop()
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
concurrency/asyncioIssues related to concurrency (asyncio-only)Issues related to concurrency (asyncio-only)externalRoot cause pending resolution in an external dependencyRoot cause pending resolution in an external dependency
Activity
lovelydinosaur commentedon Jan 2, 2020
Any idea if this replicates with
trioas well, or if it isasynciospecfic?Could really do with reducing this down to a more replicable example. 😃
florimondmanca commentedon Jan 2, 2020
@tomchristie I believe this is an asyncio-specific error — really just a StreamReader or StreamWriter not being closed before getting GC’d.
Agreed that the reproduction example could benefit from a drastic cut down... Probably you can setup a minimal test server with Uvicorn, and then work out what’s the minimal script that allows to reproduce the issue? Eg this might be: create a client without context manager syntax, make a request, and skip closing the client.
florimondmanca commentedon Jan 2, 2020
Of course this won’t be the reason of this bug, because your code is only using the high-level API. But there might be an issue with redirects, start-TLS, proxies or other places when we might be switching an asyncio stream for another one... At this point it depends on your exact setup, which you can try to replicate in a slimmed down locally maybe?
euri10 commentedon Jan 2, 2020
I'd be happy to slim it down, but I'm not sure how I could: I'm implementing a websub subscriber with FastAPI, it works fine, and the error I describe is just in my tests so maybe it's the way I'm testing things, or the way httpx calls may be intereleaved.
Maybe after you get the desrciption of the app and a picture of what it does you may help me slimming down the part that triggers the error.
https://websub.rocks/subscriber/100that is parsed to reveal the "real" address to hit,https://websub.rocks/blog/100/WBj716u7rareKpjbfoh9https://websub.rocks/blog/100/XXXa. httpx.get to the
https://websub.rocks/blog/100/XXXabove, it reveals another url, the hub_urlb. httpx.post call to the hub_url, it should return a 202 and if it's the case the /subscribe route returns 200
1-3 is really test preparation
4-6 is well represented in the image below, that's the 1st 3 horizontal arrows from the top
euri10 commentedon Jan 2, 2020
note that the error happens between 5a and 5b
lovelydinosaur commentedon Jan 15, 2020
I happened to be able to replicate this when testing an ASGI proxy... https://gist.github.com/tomchristie/5765e10a90a41c7e57470e2dc700f9db
Turns out it only replicates on Python 3.8.0. Does not replicate on 3.7.1 or 3.8.1.
It's a Python bug - here: https://bugs.python.org/issue38529
I think we can assume that we wouldn't be seeing this issue if we were using
.wait_closed()on stream closing, but we can't because there's a different asyncio Python bug there. #634We probably ought to file an
asyncioissue based on the content in #634.In the meantime - upgrade to 3.8.1. At least our exposure here is only on 3.8.0.
lovelydinosaur commentedon Jan 15, 2020
Options here:
AsyncClientunder asyncio on 3.8.0.AsyncClientunder asyncio on 3.8.0.florimondmanca commentedon Jan 15, 2020
Well, if 3.8.0 is broken on this, then I guess there's not much we can do? We can't even catch this since it's issued by asyncio on interpreter exit… So… "It's a Python bug" + "See this issue for reference"? 🤷♂
lovelydinosaur commentedon Jan 30, 2020
Going to close this off for now as it's a Python bug, not us.
If we find we're getting the same issue re-raised, then we could consider if we want to add some more explicit warnings under 3.8.0 + asyncio.