Replies: 6 comments 5 replies
-
I don't that's what aiohttp does, there must be some other issue with the code. Can you create a full reproducer, so we can just copy/paste and run it? |
Beta Was this translation helpful? Give feedback.
-
Thanks for your reply. I can reproduce the case by the following code. Server side. import asyncio
import aiohttp
async def handle_sleep_post(request):
data = await request.json()
sleep_duration=int(data["sleep_duration"])
await asyncio.sleep(sleep_duration)
return web.json_response(data)
if __name__ == "__main__":
app = web.Application()
app.add_routes(
[
web.post("/sleep", handle_sleep_post),
]
)
web.run_app(
app,
shutdown_timeout=900.0,
keepalive_timeout=750.0,
backlog=1000,
reuse_address=True,
reuse_port=True,
) The server receives POST and sleeps the assigned number of seconds by asyncio.sleep client side. The "url" in the code is the server's address in the running time. import aiohttp
import asyncio
import time
headers = {"Content-Type": "application/json"}
req = {"sleep_duration": 100}
timeout = aiohttp.ClientTimeout(total=300, connect=300, sock_connect=300, sock_read=300, ceil_threshold=300)
async def main():
async with aiohttp.ClientSession() as session:
start_point = time.perf_counter()
async with session.post(url, json=req, headers=headers, timeout=timeout) as resp:
print(resp.status)
print(await resp.text())
end_point = time.perf_counter()
print(f"{end_point - start_point}")
asyncio.run(main()) The client sends the request, which includes "sleep_duration" to specify the number of seconds for sleep. If sleep_duration is greater than 90, the error occurs as follows.
|
Beta Was this translation helpful? Give feedback.
-
More info for this case, hope supply more clues.
curl https://xx.xx.xx.xx/sleep \
-H "Content-Type: application/json" \
-d '{"sleep_duration": 200}' That makes me wonder whether I need to set something in either session or post method. However I try to go through the document and can't find anything. |
Beta Was this translation helpful? Give feedback.
-
@Dreamsorcerer Thanks for your reply. I continue to dive down this issue, and find that the issue can disappear if I try to set socket options, e.g. (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), (socket.SOL_TCP, socket.TCP_KEEPIDLE, 20), and so on. That can explain why the curl program can work in this case, which maybe set these options by default. So the question turns to, how to set these socket options into aiohttp session? Could you give me a hand for this? Thanks you again. |
Beta Was this translation helpful? Give feedback.
-
I use the following socket options.
Could you help take a look for these options in the code of aiohttp? Furthermore, is there any interface I can call to set them in my code? Thanks. |
Beta Was this translation helpful? Give feedback.
-
7200 keepidle is too long, actually in the most of environments the idle connection will be closed over 90 seconds. Even if we hope to relieve the load of servers, keepidle should be less than 90. I have to turn to other solution for my case by using streaming. In streaming way, the server can return its first part of response in 90 seconds. Is there any links for streaming in aiohttp serverside? Thanks. |
Beta Was this translation helpful? Give feedback.
-
I use the aiohttp as http server on LINUX and return the response. My code looks like:
async def handle_post(request):
loop = asyncio.get_running_loop()
handle_fn = functools.partial(call_service, await request.json())
my_result = await asyncio.wait_for(
loop.run_in_executor(None, handle_fn),
timeout=300.0,)
return web.Response(text=my_result, status=200)
if __name__ == "__main__":
app = web.Application()
app.add_routes([
web.post("/post", handle_post),
])
web.run_app(app)
My function "call_service" needs long time (almost 250s) to run so I put it into executor for parallel. However, my client, also use aiohttp session, enters the following error.
Traceback (most recent call last):
File "/home/chris/testspace/test_2_t.py", line 34, in
asyncio.run(main())
File "/home/chris/miniconda3/lib/python3.10/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/home/chris/miniconda3/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
return future.result()
File "/home/chris/testspace/test_2_t.py", line 30, in main
async with session.post(url, json=req, headers=headers, timeout=timeout) as resp:
File "/home/chris/miniconda3/lib/python3.10/site-packages/aiohttp/client.py", line 1353, in aenter
self._resp = await self._coro
File "/home/chris/miniconda3/lib/python3.10/site-packages/aiohttp/client.py", line 684, in _request
await resp.start(conn)
File "/home/chris/miniconda3/lib/python3.10/site-packages/aiohttp/client_reqrep.py", line 999, in start
message, payload = await protocol.read() # type: ignore[union-attr]
File "/home/chris/miniconda3/lib/python3.10/site-packages/aiohttp/streams.py", line 640, in read
await self._waiter
aiohttp.client_exceptions.ClientOSError: [Errno 104] Connection reset by peer.
If I use simple mock function as "call_service" and return quickly, everything is OK. But if the call_service works long, the above occurs again.
It looks the connection is closed for lack of message too long. Is there any setting I can use to avoid this issue? Thanks a lot.
Beta Was this translation helpful? Give feedback.
All reactions