I have a goroutine that is acting as a listener. A stream of input is coming in on a certain buffered channel, and I want my goroutine to process data as it comes in on that channel. However, there may come a time where no data comes in on that channel for awhile. If the channel has nothing to offer for one second, I want my goroutine to do something different. The function looks like this:
func main () {
var wg sync.WaitGroup
arr := make([]*myObject, 0)
wg.Add(1)
go listener(c, arr, &wg)
for {
// sending stuff to c
}
}
func listener(c chan *myObject, arr []*myObject, wg *sync.WaitGroup) {
for {
select {
case value := <- c:
arr = append(arr, value)
case <- time.After(1 * time.Second):
fmt.Println(arr)
}
}
The problem is that I want to see everything that went through the channel printed out. If main finishes suddenly, there might be some stuff left in arr that hasn't been printed out yet, and I won't see it. So I need to make sure that this goroutine is finished processing all the data in the channel before the program finishes. That means, I think, that I need to use a WaitGroup and use Wait() to ensure that the program doesn't close before my goroutine is done doing what it needs to do. But I can't figure out where to call Done() on my WaitGroup.
Basically, I need a safe way to "pause" the goroutine at the end, before the program finishes, and print out whatever is left. How can I do that?
Even worse, for things like unit tests, I send the data to the channel myself, and after I've sent a certain amount, I want to see the array. But if I just check the array immediately after the code to send the data to the channel, the goroutine may not have had a chance to process all the data yet. In that case, I want to wait for the goroutine to process all the data I've sent, and then I want to pause it and ask it to show me the array. But how do I know when the goroutine is finished processing? I could sleep for awhile and give it a chance to finish, and then stop it and have a look, but that feels rather hackish. I'm thinking there's a best-practice way to handle this, but I'm not figuring it out.
Here are some ideas I had, zero of which work.
Call
Done()outside of the infiniteforloop. This doesn't work, because that code, as far as I know, is unreachable.Call
Done()in the timeoutcase. This doesn't work, because there may be more data on the way after a timeout, which I want my goroutine to keep listening for.
Modify the listener to return when the channel is closed. Call wg.Done() on return:
Modify the main to close the channel when done sending. Wait for the goroutine to complete before returning from main.