TLS Requests version
latest 1.2.5
Issue description
Summary
When using tls_requests.AsyncClient with async with and await client.get() / await client.post(), the event loop is blocked. Multiple concurrent tasks behave like sequential execution (total time ≈ single request time × number of requests), so there is no real async concurrency.
Expected behavior
- Several
await client.get(...) calls from different asyncio tasks should run concurrently.
- Total time for N requests to a 2s-delay endpoint should be ~2–4s, not ~2s × N.
Actual behavior
- Only one request effectively runs at a time.
- Example: 20 concurrent requests to
https://httpbin.org/delay/2 take ~65s (≈ 20 × 3.2s) instead of ~3–4s.
- Replacing
AsyncClient with the sync Client and running it in a thread pool via asyncio.run_in_executor() gives the expected concurrency (~3–4s for 20 requests).
Minimal repro
import asyncio
import time
import tls_requests
URL = "https://httpbin.org/delay/2"
async def one(i):
async with tls_requests.AsyncClient(timeout=30, verify=False, client_identifier="chrome_133") as client:
r = await client.get(URL, timeout=30)
return getattr(r, "status_code", 0)
async def main():
start = time.perf_counter()
results = await asyncio.gather(*[one(i) for i in range(20)])
print(f"Total: {time.perf_counter() - start:.1f}s (expected ~2–4s if concurrent)")
print("Status codes:", results[:5])
asyncio.run(main())
- Observed: Total time ~60–65s.
- Expected (if truly async): Total time ~2–4s.
Environment
- Python: 3.x
- Package:
wrapper-tls-requests (e.g. from PyPI)
- OS: Windows (or your OS)
Question
Is AsyncClient intended to be non-blocking? If the underlying implementation is synchronous (e.g. Go TLS client called via sync bindings), would it be possible to document that and/or run the blocking part in a thread pool inside the library so that await client.get/post does not block the event loop?
Thanks for maintaining the project.
Steps to reproduce / Code Sample
import asyncio
import time
import tls_requests
URL = "https://httpbin.org/delay/2"
async def one(i):
async with tls_requests.AsyncClient(timeout=30, verify=False, client_identifier="chrome_133") as client:
r = await client.get(URL, timeout=30)
return getattr(r, "status_code", 0)
async def main():
start = time.perf_counter()
results = await asyncio.gather(*[one(i) for i in range(20)])
print(f"Total: {time.perf_counter() - start:.1f}s (expected ~2–4s if concurrent)")
print("Status codes:", results[:5])
asyncio.run(main())
TLS Requests version
latest 1.2.5
Issue description
Summary
When using
tls_requests.AsyncClientwithasync withandawait client.get()/await client.post(), the event loop is blocked. Multiple concurrent tasks behave like sequential execution (total time ≈ single request time × number of requests), so there is no real async concurrency.Expected behavior
await client.get(...)calls from different asyncio tasks should run concurrently.Actual behavior
https://httpbin.org/delay/2take ~65s (≈ 20 × 3.2s) instead of ~3–4s.AsyncClientwith the syncClientand running it in a thread pool viaasyncio.run_in_executor()gives the expected concurrency (~3–4s for 20 requests).Minimal repro
Environment
wrapper-tls-requests(e.g. from PyPI)Question
Is
AsyncClientintended to be non-blocking? If the underlying implementation is synchronous (e.g. Go TLS client called via sync bindings), would it be possible to document that and/or run the blocking part in a thread pool inside the library so thatawait client.get/postdoes not block the event loop?Thanks for maintaining the project.
Steps to reproduce / Code Sample