ZMQ pub/sub subscribe - node.js

I am having trouble figuring out how to subscribe to a particularly "channel" with ZMQ with regard to its pub/sub functionality.
Here is the publisher:
var zmq = require('zmq');
var pub = zmq.socket('pub');
pub.bindSync('tcp://127.0.0.1:5555');
setInterval(function(){
pub.send('pub msg');
},500);
here is the subscriber:
var sub = zmq.socket('sub');
sub.connect('tcp://127.0.0.1:5555');
sub.subscribe(''); //herein lies the question
sub.on('message',function(msg){
console.log('Received msg:',msg);
}
This works as is, but the problem is that if I change the argument to sub.subscribe to anything but an empty string (''), the subscriber doesn't receive any messages from the publisher.
How do I configure pub/sub with ZMQ correctly?

sub.subscribe('topic') adds a filter to your subscriber socket so that you only receive messages starting with the string topic. You can add multiple filters by calling it more than once. sub.subscribe('') removes any existing filter so your subscriber gets all messages sent by the publisher.
In your code using sub.subscribe('pub') would yield messages on the subscriber side.
The pub/sub example in the zeromq.node GitHub is a good place to look to understand how subscriptions work.

Related

Redis punsubscribe not unsubscribing

I have one redis client for pub-sub. I'm using a websocket message handler to dynamically subscribe to a redis channel. The payload of the websocket message contains an ID that I use to create the channel-name. So for example lobby:${lobbyID}:joined.
Subscribing to this channel works fine, messages are received when publishing to that channel.
But the issue that I'm having is that I want to unsubscribe from this channel at one point. My assumption by reading the redis-documentation is that I would use punsubscribe so I can unsubscribe from any channels with the pattern lobby:*:joined, but messages are still received after trying that.
import redis from 'redis';
const subClient = redis.createClient();
subClient.on('message', (channel, message) => {
// Received message x on channel y
});
const socketHandlerSubscribe = (lobbyID) => {
subClient.subscribe(`lobby:${lobbyID}:joined`);
}
const socketHandlerUnsubscribe = () => {
subClient.punsubscribe('lobby:*:joined'); // true
}
When using the redis-cli the pattern seems valid when using PUBSUB CHANNEL lobby:*:joined. I could solve this issue by passing a lobby ID to the unsubscribe handler aswell, but punsubscribe should be the solution for it.
I also encountered this earlier with a scenario where I looped through an array of user ID's and created a subscription for each on statuses:${userID} and tried a punsubscribe on statuses:*, without any success.
Am I doing something wrong or this is an issue node-redis related? I'm using redis version 2.8.0
I noticed that there are two different types of subscriptions. On channels and patterns. In my question I was subscribing to a channel, and unsubscribing on a pattern, these two are not 'compatible' so this won't work.
I used nc to debug this, as redis-cli won't allow additional commands when entering subscribed state.

How to sent acknowledgement after recieving a message in nodejs mqtt client package?

I am working on a communication module in which server sent data to mqtt and another client module recieves the message from mqtt. Here I need an acknowledgement from mqtt nodejs client after recieving a message so that i can delete the message from server queue.
I am using nodejs mqtt client package(https://www.npmjs.com/package/mqtt#publish). Is there a default acknowledgement function for mqtt package.
client.handleMessage = (packet: any, callback) => {
console.log(packet);
};
In the above code inside handle message is there a callback function to return a default acknowledgement to server.
No.
There is no end to end delivery notification in MQTT.
If you want to notify the publisher that a* subscriber has handled a message you will need to handle all of that yourself by publishing another message.
As on MQTT v5 there is a message header flag to indicate that a message is a direct response to a previous message, but you still have to publish this yourself.
*it is important to remember that there and be anything from 0 to many subscribers to a given topic

Redis pub/sub - same process listening to one channel

I have a single Node.js server - I would like for the process to listen to messages sent from itself - this is for testing only. The problem I am having is that when publishing a message to the same process, the subscriber doesn't seem to receive it at all.
I have this setup:
var redis = require('redis');
var rcPub = redis.createClient();
var rcSub = redis.createClient();
var message = String('testing123');
rcSub.subscribe('redis_channel#test_overall_health');
rcSub.on('message', function (channel, msgs) {
console.log(channel,msgs);
});
rcPub.publish('redis_channel#test_overall_health', message);
I have one redis client that acts as a subscriber and one as a publisher, which is the way you must do it, but for some reason the messages aren't being received. Is there some limitation that a process can't listen to the messages it publishes? It doesn't seem to make sense. I can verify this code is more or less right because other processes listening to the same channel received the message.
Apparently, the SUBSCRIBE command is being sent after the PUBLISH command.
Node's Redis client queues commands until a connection is established to the Redis server and flushes the queued commands to the server when a connect event is received on the socket. The client that initiated the connection first (publisher), will most likely receive the connect event first, at which point it will send its queued commands (publish). Because Redis processes commands in a single thread, the subscriber SUBSCRIBEs only after the PUBLISH command is complete. The other processes are able to receive the messages since they've already subscribed to this channel.
Creating the subscriber client first should work in most cases, albeit a safer approach will be to wait for the subscription to complete before publishing any messages:
var redis = require('redis');
var publisher = redis.createClient(),
subscriber = redis.createClient(),
message = 'testing123';
subscriber.subscribe('redis_channel#test_overall_health');
subscriber.on('message', function (channel, message) {
console.log(channel, message);
});
subscriber.on('subscribe', function (channel, count) {
publisher.publish('redis_channel#test_overall_health', message);
});

How to subscribe to multiple channels on Redis NodeJS

I have a function which I will call from time to time.
function blah() {
sub.unsubscribe();
sub.subscribe("a");
sub.subscribe("b");
}
Above results in error message "Error: node_redis command queue state error."
Same as https://github.com/mranney/node_redis/issues/137
Once a connection is subscribed, it can only issue subscription related commands (subscribe, psubscribe, etc)
Might another part of your code be using the same connection?
You could also try and subscribe to multiple channels with one call sub.subscribe("a", "b") or subscribe to a pattern that matches your need?
I am currently using redis.I was also facing the same issue in which i was trying to subscribe a set of channels.
var redis = require('redis')
const subscribe = redis.createClient({
host: 'localhost',
port: 6379
})
subscribe.psubscribe(`user:chat:*`)
subscribe.on('pmessage', function(pattern, channel, message) {
console.log(channel, message, pattern)
// Write Your Awesome Code here.
})
Psubscribe used for subscribing for multiple channels using redis. You can subscribe multiple channel on the basis of pattern.

node.js + socket.io broadcast from server, rather than from a specific client?

I'm building a simple system like a realtime news feed, using node.js + socket.io.
Since this is a "read-only" system, clients connect and receive data, but clients never actually send any data of their own. The server generates the messages that needs to be sent to all clients, no client generates any messages; yet I do need to broadcast.
The documentation for socket.io's broadcast (end of page) says
To broadcast, simply add a broadcast flag to emit and send method calls. Broadcasting means sending a message to everyone else except for the socket that starts it.
So I currently capture the most recent client to connect, into a variable, then emit() to that socket and broadcast.emit() to that socket, such that this new client gets the new data and all the other clients. But it feels like the client's role here is nothing more than a workaround for what I thought socket.io already supported.
Is there a way to send data to all clients based on an event initiated by the server?
My current approach is roughly:
var socket;
io.sockets.on("connection", function (s) {
socket = s;
});
/* bunch of real logic, yadda yadda ... */
myServerSideNewsFeed.onNewEntry(function (msg) {
socket.emit("msg", { "msg" : msg });
socket.broadcast.emit("msg", { "msg" : msg });
});
Basically the events that cause data to require sending to the client are all server-side, not client-side.
Why not just do like below?
io.sockets.emit('hello',{msg:'abc'});
Since you are emitting events only server side, you should create a custom EventEmitter for your server.
var io = require('socket.io').listen(80);
events = require('events'),
serverEmitter = new events.EventEmitter();
io.sockets.on('connection', function (socket) {
// here you handle what happens on the 'newFeed' event
// which will be triggered by the server later on
serverEmitter.on('newFeed', function (data) {
// this message will be sent to all connected users
socket.emit(data);
});
});
// sometime in the future the server will emit one or more newFeed events
serverEmitter.emit('newFeed', data);
Note: newFeed is just an event example, you can have as many events as you like.
Important
The solution above is better also because in the future you might need to emit certain messages only to some clients, not all (thus need conditions). For something simpler (just emit a message to all clients no matter what), io.sockets.broadcast.emit() is a better fit indeed.

Resources