Implementing the concept of "events" (with notifiers/receivers) in Golang?

Issue

I’m wondering what is the proper way to handle the concept of “events” (with notifiers/receivers) in Golang. I suppose I need to use channels but not sure about the best way.

Specifically, I have the program below with two workers. Under certain conditions, “worker1” goes in and out of a “fast mode” and notify this via channels. “worker2” can then receive this event. This works fine, but then the two workers are tightly coupled. In particular, if worker2 is not running, worker1 gets stuck waiting when writing to the channel.

What would be the best way in Golang to implement this logic? Basically, one worker does something and notify any other worker that it has done so. Whether other workers listen to this event or not must not block worker1. Ideally, there could be any number of workers that could listen to this event.

Any suggestion?

var fastModeEnabled = make(chan bool)
var fastModeDisabled = make(chan bool)

func worker1() {
    mode := "normal"
    for {
        // under some conditions:
        mode := "fast"
        fastModeEnabled <- true

        // later, under different conditions:
        mode := "normal"
        fastModeDisabled <- true
    }
}

func worker2() {
    for {
        select {

        case <-fastModeEnabled:

            fmt.Println("Fast mode started")

        case <-fastModeDisabled:

            fmt.Println("Fast mode ended")

        }
    }
}

func main() {
    go worker2()
    go worker1()

    for {}
}

Solution

Use a non-blocking write to the channel. This way if anyone is listening they receive it. If there is no one listening it doesn’t block the sender, although the event is lost.

You could use a buffered channel so that at least some events are buffered if you need that.

You implement a non-blocking send by using the select keyword with a default case. The default makes it non-blocking. Without the default case a select will block until one of its channels becomes usable.

Code snippit:

select {
    case ch <- event:
        sent = true
    default:
        sent = false
}

Answered By – Zan Lynx

Answer Checked By – Timothy Miller (GoLangFix Admin)

Leave a Reply

Your email address will not be published.