NATS Weekly #10

Byron Ruth

Published on Jan 24th, 2022

Week of January 17 - 23, 2022

🗞 Announcements, writings, and projects

A short list of  announcements, blog posts, projects updates and other news.

âš¡Releases

📖 Articles

💬 Discussions

Github Discussions from various NATS repos.

💡 Recently asked questions

Questions sourced from Slack, Twitter, or individuals. Responses and examples are in my own words, unless otherwise noted.

What are my options for subscribing to a set of subjects?

Currently, a NATS subscription (core NATS or on behalf of a JetStream consumer) can only subscribe to one subject. This can often be designed around using subject hierarchies by publishers (temp.us.east.atlanta) and then wildcards in the subscription subject such as temp.us.east.* which would match all publishing cities on the east cost of the US.

What if you only want two specific cities, like atlanta and newyork? The first thing you need to ask yourself is why do you want to choose these two subjects specifically? What makes them distinct from the other cities? Is it that they get many more temperature readings than other cities and you need a dedicated subscription? Is this acting more like a query to hone in on just these two cities and ignore everything? Some of these questions could influence the subject design up front, but we may need to work with what we got.

There are two options, one is to setup two subscriptions, one for each city and then handle these messages concurrently.

nc.Subscribe("temp.us.east.atlanta", func(msg *nats.Msg) { ... })

nc.Subscribe("temp.us.east.newyork", func(msg *nats.Msg) { ... })

And of course you could factor out the message handler as a standalone function to reuse between the two subscriptions.

If you find your self setting up many subscriptions for looping through a large number of subjects to create subscriptions for each, it may be simpler (and more performant) to just use a wildcard and drop messages with subjects you don't care about.

nc.Subscribe("temp.us.east.*", func(msg *nats.Msg) {
  switch msg.Subject {
  case "temp.us.east.atlanta":
  case "temp.us.east.newyork":
  // etc..
})

In Go, you could also use the ChanSubscribe method to funnel messages into a channel that can be incorporated in other local pipelines:

ch := make(chan *nats.Msg, 64)
nc.ChanSubscribe("temp.us.east.atlanta", ch)
nc.ChanSubscribe("temp.us.east.newyork", ch)

for {
  select {
  case msg := <-ch
    // Handle..
  }
}

To summarize, you can either add as many separate subscriptions as necessary or over-subscribe and drop messages that are not of interest. The former is likely safer to start with until you start initializing so many subscriptions that a wildcard may be then easier (and more performant).

Is a leaf node a single point of failure?

A key feature of NATS is the ability to deploy a leaf node that can act as a bridge communication to a primary cluster (or supercluster). The leaf node is local to an application (like a sidecar) which handles the majority of the messaging needs.

However, if there are subjects of interest available in external clusters, a leaf node can be setup to import streams or services and transparently expose those to local clients.

The question is whether only a single node can be deployed as leaf to the primary cluster.. and it does not! A local cluster can be deployed where each node is configured to establish a leaf connection to the primary.

One example where this may be desirable is if the application requires local replicated streams (via JetStream). Even if the leaf cluster is disconnected from the primary, it will still be highly available for the application.