NATS Logo by Example

Core Publish-Subscribe in Messaging

This example demonstrates the core NATS publish-subscribe behavior. This is the fundamental pattern that all other NATS patterns and higher-level APIs build upon. There are a few takeaways from this example:

  • Delivery is an at-most-once. For MQTT users, this is referred to as Quality of Service (QoS) 0.
  • There are two circumstances when a published message won’t be delivered to a subscriber:
    • The subscriber does not have an active connection to the server (i.e. the client is temporarily offline for some reason)
    • There is a network interruption where the message is ultimately dropped
  • Messages are published to subjects which can be one or more concrete tokens, e.g. greet.bob. Subscribers can utilize wildcards to show interest on a set of matching subjects.
CLI Go Python JavaScript Rust C# Java Ruby Elixir Crystal C
Jump to the output or the recording
$ nbe run messaging/pub-sub/crystal
View the source code or learn how to run this example yourself

Code

require "nats"

Get the passed NATS_URL or fallback to the default. This can be a comma-separated string. We convert it to an Array(URI) to pass to the NATS client.

servers = ENV.fetch("NATS_URL", "nats://localhost:4222")
  .split(',')
  .map { |url| URI.parse(url) }

Create a client connection to an available NATS server.

nats = NATS::Client.new(servers)

When the program exits, we close the NATS client which waits for any pending messages (published or in a subscription) to be flushed.

at_exit { nats.close }

To publish a message, simply provide the subject of the message and encode the message payload. NATS subjects are hierarchical using periods as token delimiters. greet and joe are two distinct tokens.

nats.publish "greet.bob", "hello"

Now we are going to create a subscription and utilize a wildcard on the second token. The effect is that this subscription shows interest in all messages published to a subject with two tokens where the first is greet.

nats.subscribe "greet.*" do |msg|
  puts "#{String.new(msg.body)} on subject #{msg.subject}"
end

Let’s publish three more messages which will result in the messages being forwarded to the local subscription we have.

nats.publish "greet.joe", "hello"
nats.publish "greet.pam", "hello"
nats.publish "greet.sue", "hello"

Output

hello on subject greet.joe
hello on subject greet.pam
hello on subject greet.sue

Recording

Note, playback is half speed to make it a bit easier to follow.