You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This bug occurs after certain async cancellations, and causes the HTTP pool to get stuck in a degraded state, unable to issue requests. It looks like a resurfacing of this issue.
httpcore version: 1.0.5
python version: 3.12.4
Code to reproduce:
importrandomimportasyncioimporthttpcorefromcollectionsimportdefaultdict# Global dictionary to store status code countsstatus_counts=defaultdict(int)
asyncdefmake_request(pool):
try:
response=awaitpool.request(
method="GET",
url=("https://localhost:8000/"),
)
status_counts[response.status] +=1exceptBaseException:
status_counts[0] +=1asyncdefspawn_and_cancel_tasks(pool):
whileTrue:
tasks= [asyncio.create_task(make_request(pool)) for_inrange(100)]
awaitasyncio.sleep(random.random()) # Allow some time for the tasks to startfortaskintasks:
task.cancel()
awaitasyncio.gather(*tasks, return_exceptions=True)
asyncdefmonitor_stats(pool):
whileTrue:
status_str=", ".join(f"{code}: {count}"forcode, countinsorted(status_counts.items()))
print(f"Status codes: {status_str} | Pool {pool}")
status_counts.clear()
awaitasyncio.sleep(1)
asyncdefmain():
asyncwithhttpcore.AsyncConnectionPool() aspool:
stats_task=asyncio.create_task(monitor_stats(pool))
spawn_task=asyncio.create_task(spawn_and_cancel_tasks(pool))
try:
awaitasyncio.gather(stats_task, spawn_task)
exceptKeyboardInterrupt:
print("Stopping...")
if__name__=="__main__":
asyncio.run(main())
Output:
Status codes: | Pool <AsyncConnectionPool [Requests: 0 active, 0 queued | Connections: 0 active, 0 idle]>
Status codes: 200: 200 | Pool <AsyncConnectionPool [Requests: 0 active, 0 queued | Connections: 0 active, 10 idle]>
Status codes: 0: 202, 200: 139 | Pool <AsyncConnectionPool [Requests: 62 active, 0 queued | Connections: 8 active, 2 idle]>
Status codes: 0: 142, 200: 117 | Pool <AsyncConnectionPool [Requests: 5 active, 0 queued | Connections: 5 active, 0 idle]>
Status codes: 0: 35, 200: 165 | Pool <AsyncConnectionPool [Requests: 5 active, 0 queued | Connections: 5 active, 5 idle]>
Status codes: 200: 100 | Pool <AsyncConnectionPool [Requests: 5 active, 0 queued | Connections: 5 active, 5 idle]>
Status codes: 0: 155, 200: 45 | Pool <AsyncConnectionPool [Requests: 5 active, 100 queued | Connections: 10 active, 0 idle]>
Status codes: 0: 300 | Pool <AsyncConnectionPool [Requests: 5 active, 0 queued | Connections: 10 active, 0 idle]>
Status codes: | Pool <AsyncConnectionPool [Requests: 5 active, 100 queued | Connections: 10 active, 0 idle]>
Status codes: 0: 200 | Pool <AsyncConnectionPool [Requests: 5 active, 0 queued | Connections: 10 active, 0 idle]> <- stops responding here
Status codes: 0: 100 | Pool <AsyncConnectionPool [Requests: 5 active, 100 queued | Connections: 10 active, 0 idle]>
Status codes: 0: 200 | Pool <AsyncConnectionPool [Requests: 5 active, 0 queued | Connections: 10 active, 0 idle]>
Status codes: 0: 100 | Pool <AsyncConnectionPool [Requests: 5 active, 100 queued | Connections: 10 active, 0 idle]>
Status codes: 0: 100 | Pool <AsyncConnectionPool [Requests: 5 active, 100 queued | Connections: 10 active, 0 idle]>
Status codes: 0: 200 | Pool <AsyncConnectionPool [Requests: 5 active, 100 queued | Connections: 10 active, 0 idle]>
Status codes: 0: 200 | Pool <AsyncConnectionPool [Requests: 5 active, 100 queued | Connections: 10 active, 0 idle]>
Status codes: 0: 300 | Pool <AsyncConnectionPool [Requests: 5 active, 100 queued | Connections: 10 active, 0 idle]>
You can see from the above output the point where the pool stops issuing new requests. This is reproducible using the default python http server:
echo'a'> index.html
python -m http.server
The bug applies to both asyncio and trio. However in trio it's much narrower. With asyncio it triggers almost immediately, while trio takes about 30 seconds.
Code to reproduce in trio:
importrandomimporttrioimporthttpcorefromcollectionsimportdefaultdict# Global dictionary to store status code countsstatus_counts=defaultdict(int)
asyncdefmake_request(pool):
try:
response=awaitpool.request(
method="GET",
url="http://localhost:8000/",
)
status_counts[response.status] +=1exceptBaseException:
status_counts[0] +=1asyncdefspawn_and_cancel_tasks(pool):
whileTrue:
withtrio.CancelScope() ascancel_scope:
asyncwithtrio.open_nursery() asnursery:
for_inrange(100):
nursery.start_soon(make_request, pool)
awaittrio.sleep(random.random()) # Allow some time for the tasks to startcancel_scope.cancel()
asyncdefmonitor_stats(pool):
whileTrue:
status_str=", ".join(f"{code}: {count}"forcode, countinsorted(status_counts.items(), reverse=True))
print(f"Status codes: {status_str} | Pool {pool}")
# Clear the counts for the next iterationstatus_counts.clear()
awaittrio.sleep(1)
asyncdefmain():
asyncwithhttpcore.AsyncConnectionPool() aspool:
asyncwithtrio.open_nursery() asnursery:
nursery.start_soon(monitor_stats, pool)
awaitspawn_and_cancel_tasks(pool)
if__name__=="__main__":
try:
trio.run(main)
exceptKeyboardInterrupt:
print("Stopping...")
Sorry to bring this up again; I know these types of issues suck to troubleshoot. But it's been causing issues for us in production. Please let me know if there's anything else I can do to help.
The text was updated successfully, but these errors were encountered:
This bug occurs after certain async cancellations, and causes the HTTP pool to get stuck in a degraded state, unable to issue requests. It looks like a resurfacing of this issue.
httpcore version:
1.0.5
python version:
3.12.4
Code to reproduce:
Output:
You can see from the above output the point where the pool stops issuing new requests. This is reproducible using the default python http server:
The bug applies to both asyncio and trio. However in trio it's much narrower. With asyncio it triggers almost immediately, while trio takes about 30 seconds.
Code to reproduce in trio:
Sorry to bring this up again; I know these types of issues suck to troubleshoot. But it's been causing issues for us in production. Please let me know if there's anything else I can do to help.
The text was updated successfully, but these errors were encountered: