-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix the ClientWebSocketResponse.receive
stuck for a long time if network is suddenly unavaiable.
#5860
Conversation
Please fill out the PR template with the details on what this is supposed to do. |
receive
stuck for long time even if heartbeat is failed.receive
stuck for long time even if heartbeat is failed.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #5860 +/- ##
==========================================
+ Coverage 96.75% 96.80% +0.05%
==========================================
Files 44 44
Lines 9851 9863 +12
Branches 1591 1594 +3
==========================================
+ Hits 9531 9548 +17
+ Misses 182 178 -4
+ Partials 138 137 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
…if network is suddenly interrupted. Related to aio-libs#2309; If we call `receive()` with a unlimited timeout, it will get stuck for long time, because `_pong_not_received` has no way to awake a block coroutine `receive()`. This PR add a `asyncio.Event` to awake this coroutine.
receive
stuck for long time even if heartbeat is failed.receive
stuck for long time even if heartbeat is failed.
receive
stuck for long time even if heartbeat is failed.ClientWebSocketResponse.receive
stuck for a long time if network is suddenly unavaiable.
elif is_heartbeat_failed_task in done: | ||
read_task.cancel() | ||
assert self._exception is not None | ||
raise self._exception |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that raise TimeoutError
or just return a WSMessage(WSMsgType.ERROR, ..)
message which is better.
any update? |
) | ||
is_heartbeat_failed_task: asyncio.Task[bool] = asyncio.create_task( | ||
self._is_heartbeat_failed.wait() | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need two additional tasks in order to solve this bug? Is it at all necessary to check heartbeat status, or is it sufficient to check transport.is_closing()?
The linked issue was closed, would be good if @bdraco or @Hanaasagi could confirm if this PR is no longer relevant. |
The receive resolves immediately when we know the connection is dropped now |
Very likely this issue is fixed. Please let us know if you still experience this behavior on 3.10.5 or later and we can reopen. |
What do these changes do?
This PR fix the websocket client will get stuck when a the internect is unavaiable.
How to reproduce it
Run following code, and turn off the internet after seeing the
Connected
text in the console.In my local machine, it will block ablout 8 min and get a
CLOSED
message.Explain Why
receive
method has atimeout
argument, and the default value isNone
. It means no timeout for reading from a connection. The websocket pong frame and user data frame uses the same timeout. So ifaiohttp
send a ping frame successfully, then we turn off the network. Thereceive
coroutine will be block at themsg = await self._reader.read()
. Because there are no data comes from the server.aiohttp/aiohttp/client_ws.py
Lines 213 to 238 in 184274d
Even if we call
_pong_not_received
, it doesn't cancel thereceive
coroutine.aiohttp/aiohttp/client_ws.py
Lines 101 to 106 in 184274d
The
receive
coroutine finished until aEofStream
error from the TCP Stack.What did this PR do
Add a simple flag(
asyncio.Event
)_is_heartbeat_failed
inClientWebSocketResponse
. And when callClientWebSocketResponse.receive
, it both awaitself._reader.read()
and this flag byasyntio.wait
. So if the heartbeat is failed, theClientWebSocketResponse.receive
will be awake.Are there changes in behavior for the user?
Related issue number
Fix #2309
Checklist
CONTRIBUTORS.txt
CHANGES
folder<issue_id>.<type>
for example (588.bugfix)issue_id
change it to the pr id after creating the pr.feature
: Signifying a new feature..bugfix
: Signifying a bug fix..doc
: Signifying a documentation improvement..removal
: Signifying a deprecation or removal of public API..misc
: A ticket has been closed, but it is not of interest to users.