I have PUB/SUB program using zmq broker ( node.js ).
Subscriber doesn't receive messages while subscriber is restarted and publisher is still publishing the messages. But PUB/SUB is working fine when both publisher and subscriber services are started naturally. Reason behind this is unknown.
What could possibly be wrong?
While it is impossible to cover exactly a case of an undisclosed MCVE-design of using a PUB-archetype, on Publisher side, and an unspecified number of SUB-archetype nodes on the Subscribers' sides, there is one important fact.
The Design
Yes, the Design. Having read the API, user will be sure that
ZeroMQ does not guarrantee a message delivery
ZeroMQ PUB-lisher does not wait and publishes a message for all connected SUB-scribers, not waiting for late-joiners, nor providing any queue/persistence for not connected SUB-scribers and discards all messages that were requested to PUB-lish during times there are no SUB-s connected.
Related
Is there any way to implement request-response pattern with mosca MQTT to "check reply from the client and re publish if i dont receive expected reply within expected time".
I believe this is possible in Mqtt 5, but as of now, I have to use Mosca broker with QoS 1(which support until Mqtt 3.1.1)
I am looking for a Node js workaround to achieve this.
As per my comment you can implement a request-response pattern with any MQTT broker but, prior to v5, you need to implement this yourself (either have a single reply-to topic and a message ID, or include a specific reply-to topic within each message).
Because MQTT 3.11 itself does not provide this functionality directly and there is no standard format for the MQTT payload (just some bytes!) its not possible to come up with a generic implementation (a unique id of some kind is needed within the request). This is resolved in MQTT v5 through the ability to include properties including Response Topic and Correlation Data. For earlier versions you are stuck with adding some extra information into the payload (using whatever encoding mechanism you choose).
There are a few Stack Overflow questions that might provide some insight:
MQTT topic names for request/response
RPC style request with MQTT
Other articles:
Eclipse Kura
Stock Explorer
IoT Application Development Using Request-Response Pattern with MQTT (Academic article - purchase needed to read whole thing).
Amazon device shadow MQTT topics (e.g. send message to $aws/things/thingName/shadow/get and AWS IoT responds on /get/accepted or /get/rejected).
Here are a few node packages (note: these have not been updated for some time and I have not reviewed the code):
replyer
resmetry
Even with MQTT v5 you would need to implement the idle timeout bit yourself. If you are using QOS 1/2 then the broker will take care of resending the message (until it receives a PUBACK/PUBCOMP) so resending the message may be counterproductive (lots of identical messages queued up while the comms link is down)
The summary of the workflow i have done
Adding "Correlation Id" for each message
The expected reply is stored in Redis as the Request Payload(Request with the
Correlation Id as a key) to compare response from the client.
The entry will be removed from Redis if the expected message is
equivalent to the expected response topic and payload.
Time out uses node cron jobs for each response from the client to
Server.
I am having serious problems to make messages delivery fail proof in a chat system.
Having several node.js and live communication via websocket to the clients, I use rabbit to callback the correct consumer at a specific node.
I declare my queues as {durable: true, prefetch:1, expires: 2*3600*1000, autoDelete: true}
consumerOption is {noAck: false, exclusive: false}
Once I receive a message from the server, I callback the server, get the message, and use message.ack(false)
Sometimes, a message appears with a pendent ACK in rabbit and as I would expect, the consumers stop being callbacked.
Here is my overall strategy:
1- when socket disconnects, I recover the queue using queue.recover() during the the reconnection/connection (more frequent).
2- When I send a message to the server and not receive it back, I send a message to the server to recover the queue.
3- I use the socket callback function to send the ack confirmation. On the server, I use message.ack(false) The server keeps a hashmap {[ackCode: string]: RabbitMessage} and I send the ackCode back to the server, so it can retrieve the correct message and ack it.
5- If client is not receiving any message for 2 minutes, I ask to the server to recover the queue.
The step 5 should not exist but even with this step, sometimes I send a recover queue request to the server, the server executes the command, but nothing happens and chat is freeze.
These are very difficult events to debug. I am using a Typescript library which is 3 year without any commit and this could be one of the causes.
Regarding the strategy, is it correct? Any idea on what I could be facing?
What I've learned and why I think that I couldn't use rabbit to solve the specific problem mentioned in the original post.
The domain: A "chat" where the message order is very important (some are chains) and we must be sure that the message will be delivery if/when the client is online.
The problem: We have several node.js servers, sockets are spread among them. Sockets falls all time, and it is common to a client connection that was in the first server be connected again in another. We don't use cookies, session affinity by IP won't handle the issue.
Limitations: That being said, I can't activate a consumer that is currently activated in another server, so if a customer Queue is tied to server 1 I can't activate it in server 2. And all the messages that need to be sent are tied to this specific queue.
Another limitation is that I don't have an easy way to consume queues, re-queue, to know in advance how much not ack messages I have in the queue, aggregate them and bulk send them via socket.
The solution: I am no longer using {noAck: false} and I am controlling the ack in a Redis queue. Thus, I am using Rabbit as a pub-sub, to callback the correct consumers to send the message using the socket. Rabbit wake me up, first thing I do is to put the message at the end of a redis queue. When I send a message via socket, I always start sending the messages from the beginning of the queue, regardless of the message that have just woke me up. I send the message, wait for the callback event, If it is not ok, I re-queue the messages,
After decoupling the pub-sub from the queue/ack control, I can now easily change my rabbit pub/sub from one server to another (declaring using socket.id and no more with the client queue), with no concern of loosing any message. Also, now I am capable of much more advanced operations on my queue.
As my use case don't allow me to use the full power of exchanges/binds (i have complex routing rules), I am evaluating the possibility of changing from rabbit to redis pub/sub, but in this case, I would continue to differentiate pub/sub from the queue.
After more than a month trying to make rabbit working in this scenery, I think that I was using a good technology to the wrong use case. It is much simpler now.
How do I send my message that is published to a Redis channel only to subscribed server (which is connected to the subscriber) and not to my other servers (where the required subscriber isn't connected).
I'm using Socket.IO and Redis server.
Have you read the documentation?
not programmed to send their messages to specific receivers (subscribers). Rather, published messages are characterized into channels, without knowledge of what (if any) subscribers there may be
I other words, you cannot target a specific subscriber.
Depending on what you are trying to achieve, you can consider using multiple channels, with each consumer using its own.
developing chat application using MQTT protocol, mosca (node module) and MongoDB as a database in Node.js
facing the problem of how to delete publish message and remove from all subscriber in app.
At a MQTT level you can't, once a message has been published it's will be delivered by the broker to all connected clients (and queued for disconnected clients) with a matching subscription.
The only thing that is possible is to clear a retained message to prevent the same payload being re-delivered each time the client connects. You do this by publishing a message with a null payload (and the retained bit set)
If you want to delete messages at the chat level you will have to implement this yourself with in the application.
I am using Node.js + ZeroMQ for subscribing to a certain feed using the PUB/SUB pattern.
How could i detect the condition where my publisher is disconnected? (I am connected as a subscriber)
Another thing: is there a way to get automatically messages from the past when i first connected to the publisher?
Thanks in advance
You could publish a heartbeat and if your subscriber misses one or more in-a-row you can assume that you lost the connection and try to reconnect.
To get the messages from the past you need to use a different pattern, like REQuesting those missing messages. In this case you need a way to identify which messages are missing.
In ZeroMQ's default pubsub model, there's no way for the subscriber to get messages from the past. See the ZeroMQ documentation, where you find statements like
If you start the SUB socket (i.e., establish a connection to a PUB
socket) after the PUB socket has started sending out data, you will
lose whatever it published before the connection was made. If this is
a problem, set up your architecture so the SUB socket starts first,
then the PUB socket starts publishing.
and
Pub-sub is like a radio broadcast; you miss everything before you
join, and then how much information you get depends on the quality of
your reception.