2

I am writing wrapper on top of nats client in golang, I want to take handler function which can be invoked from consumer once I get the message from nats server. I want to hold custom subscribe method until it receives the message from nats.

Publish:

func (busConfig BusConfig) Publish(service string, data []byte) error {
    pubErr := conn.Publish(service, data)
    if pubErr != nil {
        return pubErr
    }
    return nil
}

Subscribe:

func (busConfig BusConfig) Subscribe(subject string, handler func(msg []byte)) {
    fmt.Println("Subscrbing on : ", subject)

    //wg := sync.WaitGroup{}
    //wg.Add(1)
    subscription, err := conn.Subscribe(subject, func(msg *nats.Msg) {
        go func() {
            handler(msg.Data)
        }()
        //wg.Done()
    })
    if err != nil {
        fmt.Println("Subscriber error : ", err)
    }
    //wg.Wait()
    defer subscription.Unsubscribe()

}

test case:

func TestLifeCycleEvent(t *testing.T) {
    busClient := GetBusClient()
    busClient.Subscribe(SUBJECT, func(input []byte) {
        fmt.Println("Life cycle event received :", string(input))
    })

    busClient.Publish(SUBJECT, []byte("complete notification"))
}

I am seeing message is published but not subscribed, I tried to hold subscribe method using waitgroup but I think this is not the correct solution.

Ravat Tailor
  • 1,193
  • 3
  • 20
  • 44

2 Answers2

3

You don't see the message being delivered because Subscribe is an async method that spawns a goroutine to handle the incoming messages and call the callback.

Straight after calling busClient.Publish() your application exits. It does not wait for anything to happen inside Subscribe().

When you use nats.Subscribe(), you usually have a long-running application that exits in specific conditions (like receiving a shutdown signal). WaitGroup can work here, but probably not for real applications, just for tests.

You should also call Flush() method on NATS connection to ensure all buffered messages have been sent before exiting the program.

If you want a synchronous method, you can use nats.SubscribeSync()

Check out examples here: https://natsbyexample.com/examples/messaging/pub-sub/go

Jarema
  • 3,291
  • 2
  • 17
  • 30
0

For my understanding, I think in NATs we need to respond to the message even if we are not providing the reply address, so it can respond to the message.

func (busConfig BusConfig) Subscribe(subject string, handler func(msg []byte)) {
    subscription, err := conn.Subscribe(subject, func(msg *nats.Msg) {
        go func() {
            handler(msg.Data)
            msg.Respond(nil)
        }()
      })
   }
Ravat Tailor
  • 1,193
  • 3
  • 20
  • 44
  • No, that's incorrect. You don't need to respond to anything. If you respond to a message that does not have reply subject, it will return an error: `nats: message does not have a reply` – Jarema Dec 27 '22 at 12:05
  • I am not providing any reply address and I am not seeing any error, and it hold my subscribe method – Ravat Tailor Dec 28 '22 at 05:30
  • because error is not handled. Change `msg.Respond(nil)` into ```if err := msg.Respond(); err != nil { fmt.Printf("error from Respond: %v\n", err) }``` Please read my response carefully. It's about Go concurrency (and concurrency in general), not nats library. You're not waiting for the goroutine to finish, so it's race'y. – Jarema Dec 29 '22 at 13:57