Hardcoded 5 second timeout for writing pong response can cause errors
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 45/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Quiet
- Tech stack
- go
- Domain
- networking
Research direction
Start with the inbound ping flow in read.go around the opPing handler and the pong write path in write.go around the hardcoded five-second contexts. Reproduce or reason through a blocked write mutex and interrupted connection, then decide how the ping/pong timeout should behave. Done means the connection no longer fails prematurely in the reported conditions and the selected default or configuration is covered by tests.
Written by the indexing model from the issue text.
Description
An inbound ping has a hardcoded 5 second deadline to handle the incoming message and send out a pong response. The general codepath for such a scenario is:
Conn.readLoop->h.opcode==opPing->handleControl(..., opPing)->writeControl(..., opPong)
The two 5 second context-based timeouts declared here:
- https://github.com/coder/websocket/blob/9f473adfa59519d1e0295cd7a988d965085b701a/read.go#L302
- https://github.com/coder/websocket/blob/9f473adfa59519d1e0295cd7a988d965085b701a/write.go#L277
These timeouts can cause the Websocket connection to close with an unrecoverable error. I can go into more detail about the two possible situations that can cause this condition if required, but just note that the network connection is extremely poor both in reliability and speed, and the connection is generally busy sending data (chunked enough to allow the incoming ping frames to be handled for the average network speed assuming no interruptions).
failed to get reader: failed to handle control frame opPing: failed to write control frame opPong: failed to acquire lock: context deadline exceeded
The problem mostly arises when the connection is briefly interrupted or the write mutex is otherwise busy underneath an in-flight inbound ping message. This 5 second timeout is not enough to be able to write the pong response.
Proposals:
- Allow this timeout value to be configurable - at the very least for ping/pong control frames.
- Increase this hardcoded timeout to 20 seconds by default - perhaps only for ping/pong frames?
This is generally more in line with other implementations I've found that have a default value - though most do not have a default timeout at all and rely on the user to implement ping handling in their own way.
- https://websockets.readthedocs.io/en/stable/reference/asyncio/client.html#websockets.asyncio.client.connect -
open_timeout=10, ping_interval=20, ping_timeout=20, close_timeout=10 - https://socket.io/docs/v4/server-options/#pingtimeout (granted this isn't a pure Websocket library)
Definitely open to other ideas, and I'm happy to get a PR up for this, but for now I've forked the repo to change this value.
- Dominant language
- Go
- Stars
- 5.5k
- Forks
- 377
- PR merge metrics
- No merged PRs in 30d
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from coder/websocket
-
Must not wrap io.EOF Open
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
export wstest Openenhancement
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
Difficulty 4/5 3-5 days Newbie friendliness 42/100
-
Difficulty 5/5 Over a week Newbie friendliness 45/100
Similar issues
-
textual definition
Difficulty 1/5 Under an hour Newbie friendliness 90/100
geneontology/go-ontology#32653 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 75/100
-
needs design
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
-
Priority/High ready-for-agent Severity/Major Type/Bug
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100