Run a goroutine until a channel receives a message

293 views
Skip to first unread message

Sankar

unread,
Jan 13, 2021, 6:10:24 AM1/13/21
to golang-nuts
I have a function that must be executed as a go routine infinitely until a message comes in a channel. For example:

func readWebSocket(ws *websocket.socket, quit chan bool) {
  for {
     out, err =  ws.Read()
     log.Println(out, err)
  }
}

Now I call this above function as a goroutine from main such as:

go readWebSocket(ws, quit)

where I want the for loop to go on until the `quit` channel receives a message. The "select" loop seem to work only on multiple channels and not on a channel + some looping code.

One alternative that I could think of was to create a second goroutine (third if you include main) to which this readWebSocket can send the output of "ws.Read" and the select loop can be run there with two channels (the quit channel and the new channel which gets the "ws.Read" output) but that would leak this reader go-routine infinitely or makes the code more complex.

How to handle this situation gracefully in go channels, where I want a go routine to run until a channel gets a message ?

Thanks.

Gregor Best

unread,
Jan 13, 2021, 6:15:57 AM1/13/21
to Sankar, golang-nuts
Hi,

if `ws.Read` returns after a reasonable timeout, you can perform a
non-blocking receive on the quit channel to see if it has been
closed/something has been sent to it:

select {
case <-quit:
break
default:
// Nothing to do here
}

out, err := ws.Read()
/* more stuff in the loop */

Another approach would be to use a websocket library that supports
passing a context to the Read method (not sure if any of those exists).
For my usual go-to websocket library (github.com/gorilla/websocket), I
usually set a read deadline on the connection in cases like this and
more or less do the nonblocking read as above.
> --
> You received this message because you are subscribed to the Google
> Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to golang-nuts...@googlegroups.com
> <mailto:golang-nuts...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/32f04de0-4684-40eb-9b1b-8a9a7ff80602n%40googlegroups.com
> <https://groups.google.com/d/msgid/golang-nuts/32f04de0-4684-40eb-9b1b-8a9a7ff80602n%40googlegroups.com?utm_medium=email&utm_source=footer>.

--
Gregor Best
be...@pferdewetten.de

Sankar P

unread,
Jan 13, 2021, 6:18:32 AM1/13/21
to Gregor Best, golang-nuts
if `ws.Read` returns after a reasonable timeout, you can perform a
non-blocking receive on the quit channel to see if it has been
closed/something has been sent to it:

        select {
                case <-quit:
                        break
                default:
                        // Nothing to do here
        }

        out, err := ws.Read()
        /* more stuff in the loop */

This is brilliant. I feel bad that I did not think of this myself :-) Thanks.
 

Another approach would be to use a websocket library that supports
passing a context to the Read method (not sure if any of those exists).
For my usual go-to websocket library (github.com/gorilla/websocket), I
usually set a read deadline on the connection in cases like this and
more or less do the nonblocking read as above.

Yes, I too use the gorilla websocket library only. I have not touched the "context" related code as it was not part of the initial release and I never got around to understanding it. Thanks for the pointer. I will see if that would help me.

Sankar

Toon Knapen

unread,
Jan 14, 2021, 12:19:59 PM1/14/21
to golang-nuts
Note from the gorilla websocket documentation ' SetReadDeadline sets the read deadline on the underlying network connection. After a read has timed out, the websocket connection state is corrupt and all future reads will return an error. A zero value for t means reads will not time out.'  

Thus IIUC once the timeout fired, you can not just continue the loop as further reads from the ws will result in errors. However that is what the OP intends to do if my understanding is correct.

A solution to me looks to spin up a goroutine that will read from the websocket and will send what is read to a channel. Inside the loop the select might than 'case' on the quit channel and the channel fed by the ws.Read()

Reply all
Reply to author
Forward
0 new messages