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
Currently, as far as I can see, the only mechanism for getting a timeout on a ReadMessage call is by setting a read deadline with SetReadDeadline.
This works, but if a read times out due to a read deadline, the whole connection is corrupted and cannot be read from anymore(!).
This is a surprising and extremely severe result that makes the mechanism unsuitable when all you really want is to just try receiving for a while, and if no message was received, then go do other stuff, and re-try receiving on the same (intact) connection later. As far as I can tell (please correct me if I'm wrong), there is currently no way to do this, which is unfortunate.
elnappo, mpobrien, kendalharland, jjmaldonis, mnvx and 13 morerittneje
That's correct. The connection methods use local variables to maintain state as is common with Go code. That state is lost of a connection method returns because of an error on the underlying connection. The connection is no longer useable after the state is lost. The connection methods could be written to be restorable, but that will take some effort.
The solution is to use a goroutine to go off and do other work. Because the application must read the connection to process control messages (documentation), it's not a good idea to go off and do other stuff for a long time.
Yeah, in my use case the "other stuff" that I wanted to periodically do between ReadMessage calls was just a quick, non-blocking check to see if the component that consumes the messages is still interested in consuming more of them.
As an awkward workaround, I can have a separate goroutine that does the periodic checking and closes the websocket connection when the component isn't interested in consuming additional messages anymore, and then make sure I handle the resulting expected read errors specially. It would just be nicer if this awkward workaround with an additional goroutine and error handling wasn't necessary. :)
When the component is no longer interested in receiving messages, the application should send a close message to the peer. The peer will echo the message back and that message will be returned as an error from the websocket connection's read API. If you use websocket.CloseNormalClosure or some other expected error code, no special error handling should be required.
The application should force close the connection after a timeout to handle the case where the peer does not correctly echo the close message back to the application.
@garyburd: Hmm, is it normal for you to close tickets without stating a reason? :) In any case, is it fair to conclude from stevenscott89's comment (quoted below) that the reason for closing the ticket is that not killing the connection on read timeouts is too hard in Go?
The connection methods use local variables to maintain state as is common with Go code. That state is lost of a connection method returns because of an error on the underlying connection. The connection is no longer useable after the state is lost. The connection methods could be written to be restorable, but that will take some effort.
Hi! If I want non blocking ReadMessage (in order to be able to finish a "reader" goroutine with an external signal), how can I achieve that? I also don't want to close current connection, because it's supposed to be long-living. Thanks!
This is indeed a serious issue with the gorilla embedded net.Conn implementation and is non compliant with non blocking network reads from within a goroutine that is checking for <-ctx.Done() or other timeout conditions periodically. Then again issue #282 seems to indicate by no means is the gorilla websocket implementation attempting to be net.Conn compliant. I also would like to seem updates to this module to resolve these issues.
I want to use two set of processing methods between con life cycle statuses. I kow I can be done by use chan, and alway let on fuction (goroutine) to rev message. But for more good efficiency, maybe we can add this.
Maybe we want to cancle read operation, we can use this. I test tcp socket, and UnderlyingConn(), on the level of net.con SetReadDeadline can renew con error.
After so many years of non-blocking I/O for everything net.Conn based, this was somewhat shocking to run into in this package. I see there are clear comments in the code on SetReadDeadline, but this feels worthy of proper documentation in the readme or somewhere else.
Activity
ghost commentedon Jan 27, 2019
That's correct. The connection methods use local variables to maintain state as is common with Go code. That state is lost of a connection method returns because of an error on the underlying connection. The connection is no longer useable after the state is lost. The connection methods could be written to be restorable, but that will take some effort.
The solution is to use a goroutine to go off and do other work. Because the application must read the connection to process control messages (documentation), it's not a good idea to go off and do other stuff for a long time.
Eelis commentedon Jan 28, 2019
Yeah, in my use case the "other stuff" that I wanted to periodically do between ReadMessage calls was just a quick, non-blocking check to see if the component that consumes the messages is still interested in consuming more of them.
As an awkward workaround, I can have a separate goroutine that does the periodic checking and closes the websocket connection when the component isn't interested in consuming additional messages anymore, and then make sure I handle the resulting expected read errors specially. It would just be nicer if this awkward workaround with an additional goroutine and error handling wasn't necessary. :)
ghost commentedon Jan 28, 2019
When the component is no longer interested in receiving messages, the application should send a close message to the peer. The peer will echo the message back and that message will be returned as an error from the websocket connection's read API. If you use websocket.CloseNormalClosure or some other expected error code, no special error handling should be required.
The application should force close the connection after a timeout to handle the case where the peer does not correctly echo the close message back to the application.
Eelis commentedon Feb 13, 2019
@garyburd: Hmm, is it normal for you to close tickets without stating a reason? :) In any case, is it fair to conclude from stevenscott89's comment (quoted below) that the reason for closing the ticket is that not killing the connection on read timeouts is too hard in Go?
aspotashev commentedon Aug 16, 2019
This would be easy to implement if we had this feature -> #481
practicode-org commentedon Aug 20, 2021
Hi! If I want non blocking ReadMessage (in order to be able to finish a "reader" goroutine with an external signal), how can I achieve that? I also don't want to close current connection, because it's supposed to be long-living. Thanks!
robertfarnum commentedon Jan 13, 2022
This is indeed a serious issue with the gorilla embedded net.Conn implementation and is non compliant with non blocking network reads from within a goroutine that is checking for <-ctx.Done() or other timeout conditions periodically. Then again issue #282 seems to indicate by no means is the gorilla websocket implementation attempting to be net.Conn compliant. I also would like to seem updates to this module to resolve these issues.
FMLS commentedon Mar 21, 2022
watching this issue
ddbxyrj commentedon Jun 7, 2022
I want to use two set of processing methods between con life cycle statuses. I kow I can be done by use chan, and alway let on fuction (goroutine) to rev message. But for more good efficiency, maybe we can add this.
Maybe we want to cancle read operation, we can use this. I test tcp socket, and UnderlyingConn(), on the level of net.con SetReadDeadline can renew con error.
shaunco commentedon Jun 3, 2025
After so many years of non-blocking I/O for everything net.Conn based, this was somewhat shocking to run into in this package. I see there are clear comments in the code on
SetReadDeadline
, but this feels worthy of proper documentation in the readme or somewhere else.