DEV Community

Cover image for Cnator: channel-based subscriptions in Go
Altiano Gerung
Altiano Gerung

Posted on

2 2

Cnator: channel-based subscriptions in Go

Channels is one of those things that makes Go awesome.

I use channels quite a lot in my next open projects. One of those scenario is to model an event-driven approach.

While developing these projects, I noticed that the setup is more or less the same, so I decided to make a Go module for that.

It's called Cnator (pronounce "c-nator")

go get gitlab.com/altiano/cnator
Enter fullscreen mode Exit fullscreen mode

It has 3 methods :

  • New()
  • Subscribe(channel, subscriber)
  • Serve()

that can be use it like this

    cnator := cnator.New()
    channels := createChannels()

    // provide channel reference to each publisher
    producerA := NewProducerA(channels.chanA)
    producerB := NewProducerB(channels.chanB)
    producerC := NewProducerC(channels.chanC)

    // using cnator to subscribe to those channel events
    subscriberA := subscriberA{}
    subscriberB := subscriberB{}
    subscriberC := subscriberC{}
    cnator.Subscribe(channels.chanA, subscriberA.receiveChanA)
    cnator.Subscribe(channels.chanB, subscriberB.receiveChanB)
    cnator.Subscribe(channels.chanC, subscriberC.receiveChanC)

     // start watching for events
    cnator.Serve()
Enter fullscreen mode Exit fullscreen mode

createChannel() just initialized the channels, but you should provide your own model

func createChannels() channels {
    return channels{
        chanA: make(chan struct{}),
        chanB: make(chan string),
        chanC: make(chan Person),
    }
}
Enter fullscreen mode Exit fullscreen mode

the subscribers are just callback functions with a matching data type with the channels

func (s *subscriberA) receiveChanA() {
    fmt.Println("Subscriber A receiving")
}

func (s *subscriberB) receiveChanB(data string) {
    fmt.Println("Subscriber B receiving", data)
}

func (s *subscriberC) receiveChanC(data Person) {
    fmt.Println("Subscriber C receiving", data)
}
Enter fullscreen mode Exit fullscreen mode

except for chanA that receive empty struct{},
you can ignore the parameter like receiveChanA() does.

The job of cnator.Serve() is to spawn a go routine for each subscription made by cnator.Subscribe(..).

It provides some runtime validation like

  • whether the subscriber function doesn't satisfy the channel data type or
  • whether the channel has not been initialized (i.e. forget to make(chan ..)) etc

Full code & examples can be found at this repository : Cnator

Also posted on : https://blog.altiano.dev/cnator-channel-based-subscription-in-go

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay