Reputation: 57
I am trying to read a constant stream of data, if the call to receive stream takes longer than 30 seconds I need to timeout and exit the program. I am not sure how to exit the go routine once a timeout has been received.
func ReceiveStreamMessages(strm Stream, msg chan<- []byte) error {
d := make(chan []byte, 1)
e := make(chan error)
tm := time.After(30 * time.Second)
go func() {
for {
//blocking call
data, err := strm.Recv()
if err != nil {
e <- err
return
}
select {
case d <- data.Result:
case <-tm:
//exit out go routine
return
}
}
}()
for {
select {
case message := <-d:
msg <- message
case err := <-e:
return err
case <-tm:
return nil
}
}
}
My code above is wrong as: in order for the select
to run in the go routines for loop, the blocking function will have to return and data will be populated and therefore won't hit the timeout select case (or will do randomly as both will be ready). Is exiting the parent function enough to exit the go routine?
Upvotes: 2
Views: 3844
Reputation: 4570
Use context
package WithTimeout
. Something like this:
package main
import (
"context"
"fmt"
"sync"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
// prepare
...
// wait group just for test
var wg sync.WaitGroup
wg.Add(1)
go func() {
for {
select {
case d <- data.Result:
// do something
case <-ctx.Done():
fmt.Println("Done")
wg.Done()
return
}
}
}()
wg.Wait()
cancel()
fmt.Println("Hello, playground")
}
You can see a working example here https://play.golang.org/p/agi1fimtEkJ
Upvotes: 3