Nats.io QueueSubscribe behavior on timeout - go

I'm evaluating NATS for migrating an existing msg based software
I did not find documentation about msg timeout exception and overload.
For Example:
After Subscriber has been chosen , Is it aware of timeout settings posted by Publisher ? Is it possible to notify an additional time extension ?
If the elected subscriber is aware that some DBMS connection is missing and cannot complete It could be possible to bounce the message
NATS server will pickup another subscriber and will re-post the same message ?
Ciao
Diego

For your first question: It seems to me that you are trying to publish a request message with a timeout (using the nc.Request). If so, the timeout is managed by the client. Effectively the client publishes the request message and creates a subscription on the reply subject. If the subscription doesn't get any messages within the timeout it will notify you of the timeout condition and unsubscribe from the reply subject.
On your second question - are you using a queue group? A queue group in NATS is a subscription that specifies a queue group name. All subscriptions having the same queue group name are treated specially by the server. The server will select one of the queue group subscriptions to send the message to rotating between them as messages arrive. However the responsibility of the server is simply to deliver the message.
To do what you describe, implement your functionality using request/reply using a timeout and a max number of messages equal to 1. If no responses are received after the timeout your client can then resend the request message after some delay or perform some other type of recovery logic. The reply message should be your 'protocol' to know that the message was handled properly. Note that this gets into the design of your messaging architecture. For example, it is possible for the timeout to trigger after the request recipient received the message and handled it but before the client or server was able to publish the response. In that case the request sender wouldn't be able to tell the difference and would eventually republish. This hints that such type of interactions need to make the requests idempotent to prevent duplicate side effects.

Related

Acknowledge messages in NSQ

I'm new to NSQ and was wondering whether it is possible to acknowledge that a message was consumed (just like in Google PubSub). I'm using Golang, and while going through the NSQ documentation (https://github.com/nsqio/nsq/blob/v1.2.1/nsqd/channel.go#L350) I've found the method FinishMessage which according to its comment, it's supposed to successfully discards an in-flight message. Would that be considered the same as acknowledged? If a message is not acknowledged in NSQ, how is it ensured it's gone once consumed so it won't be consumed over again?
Thanks
NSQ automatically removes a message from the queue after sending it to a consumer. And automatically re-queues the message if there is no response from the consumer after a set timeout.
And yes, depending on which programming language client you are using you have to send 'finish'.
Here are the docs for Golang
https://pkg.go.dev/github.com/nsqio/go-nsq#Finish
But because of the way NSQ is designed you have to re-queue a message from your app if the intended action was not successful.
Here is an excerpt from their website
NSQ guarantees that a message will be delivered at least once, though duplicate messages are possible. Consumers should expect this and de-dupe or perform idempotent operations.
This guarantee is enforced as part of the protocol and works as follows (assume the client has successfully connected and subscribed to a topic):
client indicates they are ready to receive messages
NSQ sends a message and temporarily stores the data locally (in the event of re-queue or timeout)
client replies FIN (finish) or REQ (re-queue) indicating success or failure respectively. If client does not reply NSQ will timeout after
a configurable duration and automatically re-queue the message)
You can read more here: https://nsq.io/overview/design.html
Hope my answer helps you.

Implementing Request/Reply Pattern with Spring and RabbitMQ with already existing queues

Let me start by describing the system. There are 2 applications, let's call them Client and Server. There are also 2 queues, request queue and reply queue. The Client publishes to the request queue, and the server listens for that request to process it. After the Server processes the message, it publishes it to the reply queue, which the Client is subscribed to. The Server application always publishes the reply to the predefined reply queue, not a queue that the Client application determines.
I cannot make updates to the Server application. I can only update the Client application. The queues are created and managed by the Server application.
I am trying to implement request/reply pattern from Client, such that the reply from the Server is synchronously returned. I am aware of the "sendAndReceive" approach with spring, and how it works with a temporary queue for reply purposes, and also with a fixed reply queue.
Spring AMQP - 3.1.9 Request/Reply Messaging
Here are the questions I have:
Can I utilize this approach with existing queues, which are managed and created by the Server application? If yes, please elaborate.
If my Client application is a scaled app (multiple instances of it are running at the same time), then how do I also implement it in such a way, that the wrong instance (one in which the request did not originate) does not read the reply from the queue?
Am I able to use the "Default" exchange to my advantage here, in addition to a routing key?
Thanks for your time and your responses.
Yes; simply use a Reply Listener Container wired into the RabbitTemplate.
IMPORTANT: the server must echo the correlationId message property set by the client, so that the reply can be correlated to the request in the client.
You can't. Unlike JMS, RabbitMQ has no notion of message selection; each consumer (in this case, reply container) needs its own queue. Otherwise, the instances will get random replies and it is possible (highly likely) that the reply will go to the wrong instance.
...it publishes it to the reply queue...
With RabbitMQ, publishers don't publish to queues, they publish to exchanges with a routing key. It is bad practice to tightly couple publishers to queues. If you can't change the server to publish the reply to an exchange, with a routing key that contains something from the request message (or use the replyTo property), you are out of luck.
Using the default exchange encourages the bad practice I mentioned in 2 (tightly coupling producers to queues). So, no, it doesn't help.
EDIT
If there's something in the reply that allows you to correlate it to a request; one possibility would be to add a delegating consumer on the server's reply queue. Receive the reply, perform the correlation, route the reply to the proper replyTo.

Spring AMQP synchronous reply and multithreading

I have a project where I send AMQP messages to a RabbitMQ Server. This messages are synchronous messages (I use sendAndReceive method). So, I have a SimpleMessageListenerContainer configured with the RabbitTemplate as MessageListener, and the response queue is fixed (setReplyAddress in the RabbitTemplate).
If I have a multithreading server (Tomcat) where it is possible to send some messages simultaneously, could there be a problem if the response doesn’t arrive in order or the application send a message before a response to another message has arrived?
The responses are paired with requests using correlationId header. Clients have to set it to unique value for every request and the server has to set the same value the response queue. That way a client can pair the messages even when they arrive in arbitrary order.
From the RabbitMQ tutorial:
In the method presented above we suggest creating a callback queue for every RPC request. That's pretty inefficient, but fortunately there is a better way - let's create a single callback queue per client.
That raises a new issue, having received a response in that queue it's
not clear to which request the response belongs. That's when the
correlationId property is used. We're going to set it to a unique
value for every request. Later, when we receive a message in the
callback queue we'll look at this property, and based on that we'll be
able to match a response with a request. If we see an unknown
correlationId value, we may safely discard the message - it doesn't
belong to our requests.

stomp message acknowledgement from client

I am using spring/stomp/websocket framework to notify users of messages asynchronously. I have done this successfully. However, I would be get ACK from the client so that some server side action can take place when this is done.
The flow is roughly as flows:
Service notifies a specific user about a decision and updates a record in the DB with status = "notified"
Client receives the message (using stompClient.subscribe(...))
Client acknowledges that the message was received.
The service "knows" that this message was acknowledged and updates the status to "ACK" in the DB.
stompClient.connect({login:'guest', passcode:'guest'},
function(frame) {
setConnected(true);
**var headers = {ack: 'client'};**
...
stompClient.subscribe('/user/guest/response',function(notification) {
//doSomething
}), **headers**);
}
In the service, the message is sent:
this.messagingTemplate.convertAndSendToUser(user, "/response",msg, map);
Is there a way to handle the client ACK on the server side?
Alternatively, I tried to do a
stompClient.send("/app/response/ack/"+messageId);
on the client, in the method that handles the subscription, but in vain.
Can someone please tell me what is standard way to handle acknowledgments? I have been struggling with this for a a couple of days and any thoughts would be very helpful.
Thanks!
Use the ACK frame as per spec. The server sends an ack:some_id header, the client uses that some_id in the ACK frame.
The answer is no for simple broker.
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html
The simple broker is great for getting started but supports only a
subset of STOMP commands (e.g. no acks, receipts, etc.), relies on a
simple message sending loop, and is not suitable for clustering. As an
alternative, applications can upgrade to using a full-featured message
broker.

Correct socket types for a message catchup mechanism?

I have a single publisher application (PUB) which has N number of subscribers (SUB)
These subscribers need to be able to catch up if they are restarted, or fall down and miss messages.
We have implemented a simple event store that the publisher writes to.
We have implemented a CatchupService which can query the event store and send missed messages to the subscriber.
We have implemented in the subscriber a PUSH socket which sends a request for missed messages.
The subscriber also has a PULL socket which listens for missed messages on a seperate port.
The subscriber will:
Detect a gap
Send a request for missed messages to our CatchupService, the request also contains the address on which to send the results to.
The catchup service has a PULL socket on which it listens for requests
When the CatchupService receives a request it starts a worker thread which:
Gets the missed messages
Opens a PUSH socket connecting to the subscribers PULL socket
Sends the missed messages to the subscriber.
This seems to work quite well however we are unsure if we are using the right socket types for this sort of application. Are these correct or should be using a different pattern.
Sounds okay. Otherwise 0MQ is able to recovery from message loss when peers go offline for a short time. Take a look at the Socket Options and specifically option ZMQ_SNDHWM.
I don't know just how guaranteed the 0MQ recovery mechanisms are so maybe you're best to stay with what you've got, but it is something to be aware of.

Resources