All posts

NATS Weekly #38

Week of August 1 - 7, 2022

🗞 Announcements, writings, and projects

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

⚡Releases

Official releases from NATS repos and others in the ecosystem.

⚙️ Projects️

Open Source and commercial projects (or products) that use or extends NATS.

💬 Discussions

Github Discussions from various NATS repositories.

🧑‍🎓 Examples

New or updated examples on NATS by Example .

💡 Recently asked questions

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

What exactly does the allow_responses permission do?

When defining user permissions as part of the server config or as part of a user JWT, you can optionally allow or deny the ability to publish and/or subscribe to specific subjects (including wildcards). By default, if no permissions are set, a user can publish and subscribe to all subjects (except for those reserved for exclusive use by the system account… which will be discussed another time 🙂).

Once an explicit publish or subscribe permission is defined (allow or deny), then the permission restriction kicks in. For example, here is a user without permissions ( users could be scoped under the top-level authorization block or under an explicit account, e.g. APP under the accounts block.)

users: [

{user: joe, password: s3cret}

]

This effectively allows publishing and subscribing to all subjects (barring system-account subjects by default). However, adding even one allow permission, will result in only those subjects are allowed implicitly.

For example, given these two allow permissions, now the user joe cannot publish or subscribe to any other subject. It switches from an implicit deny all + allow.

users: [

{user: joe, password: s3cret, permissions: {

subscribe: {

allow: ["events.service.>"]

},

publish: {

allow: ["events.joe.>"]

}

}}

]

Adding an explicit deny takes precedence, so messages published to  events.service.secret.> would never be received by joe even if the subscription was on a more general form of events.service.>.

users: [

{user: joe, password: s3cret, permissions: {

subscribe: {

allow: ["events.service.>"],

deny: ["events.service.secret.>"]

},

publish: {

allow: ["events.joe.>"]

}

}}

]

What about services that implement the request-reply pattern? For example:

nc.QueueSubscribe("services.greeter", func(msg *nats.Msg) {

reply := fmt.Sprintf("hello %s!", string(msg.Data))

msg.Respond([]byte(reply))

})

As a client, I can call it using the helper method.

nc.Request("services.greeter", []byte("joe"), time.Second)

Internally, this relies on a unique  INBOX.> subject generated by the client and includes it in the message for the service (subscription) to send the reply back to. This works great unless you need to lock-down cross-user snooping of messages. Specifically, you can simply subscribe to _INBOX.> and listen in on all of the replies send back from the service.

The private inbox pattern can be leveraged to require unique inbox prefixes set per client. Then the permissions can be set to enforce that.

But what does this mean for a user defined for a service? This will also need to have permissions to prevent it from doing everything. Does it now need to have explicit permission for every known inbox prefix that will be used? Not at all, this is what the allow_responses permission is for.

users: [

{user: greeter, password: s3cret2, permissions: {

subscribe: {

allow: ["services.greeter"]

},

allow_responses: true

}}

]

It essentially provides a dynamic, one-time (by default) allowance of a publish back to the reply subject (an inbox) in order to respond to the request. Beyond that, it can no longer arbitrarily publish to that same subject.

How can you recover from a stuck consumer on a interests-based stream?

Quoting the docs, an interests-based stream is retention policy where:

Messages are kept as long as there are Consumers on the stream (matching the message’s subject if they are filtered consumers) for which the message has not yet been ACKed. Once all currently defined consumers have received explicit acknowledgement from a subscribing application for the message it is then removed from the stream.

A situation came up in Slack where a user had a consumer that was in an odd state where messages were no longer being sent the subscriptions for processing. The concern was that if the consumer was removed, the interest for that consumer would be gone, which means all messages would be removed (per the definition of the retention policy).

The solution was to create a temporary consumer that had a start sequence of the last unprocessed message (un-acked) of the misbehaving consumer. From the stream’s perspective, this is new interest.

At this point it is safe to delete the first consumer and recreate it starting at the same sequence in order to restart processing. Finally the temporary consumer can be deleted since the original consumer is working again.

As an aside, although this pattern is useful for unrecoverable cases, it turned out the solution to unstick the consumer was to force a leader step down on the consumer. This can be done using nats consumer cluster step-down <stream> <consumer>.