Node-amqp example of Topic exchange - node.js

Does anyone have an example of creating a topic exchange in Node-amqp? I've already gone through https://github.com/rabbitmq/rabbitmq-tutorials/tree/master/javascript-nodejs but unfortunately it doesn't recreate tutorials 4+ from the RabbitMQ website.

This might be an over simplistic answer but at a basic level it's doable like this...
var amqp = require('amqp');
var connection = amqp.createConnection({ host: '127.0.0.1' });
connection.on('ready', function () {
var exchange = connection.exchange('my-super-xchange', {type: 'topic'});
exchange.on('open', function(){
console.log('Lets do this!');
})
})
Once you have run the above, the exchange should now be visible on your rabbitMQ instance
$ rabbitmqctl list_exchanges
Listing exchanges ...
direct
amq.direct direct
amq.fanout fanout
amq.headers headers
amq.match headers
amq.rabbitmq.log topic
amq.rabbitmq.trace topic
amq.topic topic
dingo topic
my-super-xchange topic
...done.

Related

Configuring Topic Alias for MQTT 5.0 feature Using nodejs

I am trying to implemented shared topic concept using Nodejs code.
Now I am planning to implement Topic Alias using the Nodejs Code.
I have tried with below code but I didn't get proper out:
const mqtt = require('mqtt')
const clientThree = mqtt.connect('mqtt://192.168.x.xx:1883')
var options={
topicAliasMaximum:1,
};
clientThree.on('connect', () => {
let i = 0
clientThree.publish('test', "hello",options);
})
Shared topic is share topic prefix + topic like:
# single topic
t/#
# share topic
$queue/t/#
# or
$share/group1/t/#
Topic Alias is the property of MQTT 5.0, See mqtt.js properties options:
const client = mqtt.connect({
properties: {
topicAliasMaximum: 10
}
})
// Now sub topic and set the topic subscription id
client.subscribe('t/#', { properties: { subscriptionIdentifier: 2 } })
// Now using subscription id to publish
// wait me try..

Proper way of reading messages from Kafka topic and then closing

I am building a simple node.js API using express and kafka-node that returns unread messages from requested Kafka topic and consumer group when HTTP request is received and then closes the connection. I don't need or want the consumer to keep waiting for new messages.
In kafka-node, what is the proper way of checking if the end of the topic has been reached and if yes, close the connection to broker and exit the application in order to prevent new messages being read?
Here's my consumer.js. It's pretty much the same as example given in kafka-node documentation.
"use strict";
const kafka = require("kafka-node");
let topicName = "testTopic-01",
groupName = "testGroup-01",
consumerOptions = {
kafkaHost: "localhost: 9092",
groupId: groupName,
sessionTimeout: 15000,
protocol: ["roundrobin"],
fromOffset: "earliest",
encoding: "utf8"
};
const consumerGroup = new kafka.ConsumerGroup(consumerOptions, topicName);
consumerGroup.on("message", message => {
console.log(`Message: ${message.value}`);
});
consumerGroup.on("error", error => {
console.error(error);
});
console.log(`Consumer started on topic ${topicName} on group ${groupName}`);
You can fetch the current offset of a topic partition by using #Offset. By comparing the so fetched offset of your assigned topic partition, you then know what the last message in the corresponding topic partition is.
Keep in mind, that, if you have multiple consumers in parallel, you should keep track of the topic partition that your consumer inside the consumer group was assigned to (#fetchCommits).

How to fix ServerStack RabbitMQ fanout exchange test that fails, without rewriting the whole test

I'm running all the ServiceStack tests for RabbitMQ and for the life of me I couldn't get this one "Publishing_message_to_fanout_exchange_publishes_to_all_queues" to pass. After a bit of digging and reading I've found that:
The name of the test should be changed to Topic, instead of fanout (The ServiceStack framework built in functionality doesn't provide for it).
There is no need for RegisterQueue, RegisterTopic, and RegisterDlq static methods in the test file, you should use the RabbitMqExtensions.
These two statements below actually do the same thing in essence, bind a queue to an exchange (topic) AND provide for a routing key, BUT the routing keys are different so only one of the queues gets a message published to it, so the test always fails.
RegisterTopic(channel, QueueNames<HelloRabbit>.Out);
RegisterQueue(channel, QueueNames<HelloRabbit>.In, exchange: ExchangeTopic);
I'm hoping someone could enlighten me as to whether or not this test ever passed.
Thank you, Stephen
This test was refactored incorrectly, it used to use a fanout exchange as seen in its commit history.
I've just changed it to use a fanout exchange as seen in:
[Test]
public void Publishing_message_to_fanout_exchange_publishes_to_all_queues()
{
using (IConnection connection = mqFactory.CreateConnection())
using (IModel channel = connection.CreateModel())
{
channel.RegisterFanoutExchange(ExchangeFanout);
RegisterQueue(channel, QueueNames<HelloRabbit>.In, exchange: ExchangeFanout);
RegisterQueue(channel, QueueNames<HelloRabbit>.Priority, exchange: ExchangeFanout);
byte[] payload = new HelloRabbit { Name = "World!" }.ToJson().ToUtf8Bytes();
var props = channel.CreateBasicProperties();
props.SetPersistent(true);
channel.BasicPublish(ExchangeFanout, QueueNames<HelloRabbit>.In, props, payload);
var basicGetMsg = channel.BasicGet(QueueNames<HelloRabbit>.In, noAck: true);
Assert.That(basicGetMsg, Is.Not.Null);
basicGetMsg = channel.BasicGet(QueueNames<HelloRabbit>.Priority, noAck: true);
Assert.That(basicGetMsg, Is.Not.Null);
}
}

amqp exchanges are not auto-deleted

I have rabbitmq 3.3.5 running and nodejs project based on amqplib 0.2.1
The problem is that once exchange has been asserted it does not deleted after connection to rabbitmq is closed.
If we start such example
var amqp = require('amqplib');
var when = require('when');
amqp.connect('amqp://localhost').then(function(conn) {
return when(conn.createChannel().then(function(ch) {
var ex = 'logs_new';
var ok = ch.assertExchange(ex, 'fanout', {durable: false, autoDelete: true}})
var message = process.argv.slice(2).join(' ') ||
'info: Hello World!';
return ok.then(function() {
ch.publish(ex, '', new Buffer(message));
console.log(" [x] Sent '%s'", message);
return ch.close();
});
})).ensure(function() { conn.close(); });
}).then(null, console.warn);
and run
#rabbitmqctl list_exchanges
Listing exchanges ...
amq.rabbitmq.log topic
amq.rabbitmq.trace topic
amq.topic topic
logs_new fanout
...done.
Though connection to rabbitmq was closed, but exchange (logs_new) still persists.
How to tell rabbitmq that exchange needs to be deleted if it is not used by any connection ?
edit:
As it is stated at http://www.squaremobius.net/amqp.node/doc/channel_api.html autoDelete option should be 'true'. but nevertheless even exchange with new name is not deleted. What could be wrong?
You should set the auto_delete flag to True when declaring the exchange. This will automatically delete the exchange when all channels are done with it.
Keep in mind that this means that it will stay as long as there is an active binding to the exchange. If you delete the binding, or queue, the exchange will be deleted.
If you need to keep the queue, but not the exchange you can remove the binding once you are done publishing. This should automatically remove the exchange.

how can I make private chat rooms with sockjs?

I am trying to make a chat system where only two users are able to talk to each other at a time ( much like facebook's chat )
I've tried multiplexing, using mongoDB's _id as the name so every channel is unique.
The problem I'm facing is that I cannot direct a message to a single client connection.
this is the client side code that first sends the message
$scope.sendMessage = function() {
specificChannel.send(message)
$scope.messageText = '';
};
this is the server side receiving the message
specificChannel.on('connection', function (conn) {
conn.on('data', function(message){
conn.write('message')
}
}
When I send a message, to any channel, every channel still receives the message.
How can I make it so that each client only listens to the messages sent to a specific channel?
It appeared that SockJS doesn't support "private" channels. I used the following solution for a similar issue:
var channel_id = 'my-very-private-channel'
var connection = new SockJS('/pubsub', '')
connection.onopen = function(){
connection.send({'method': 'set-channel', 'data': {'channel': channel_id}})
}
Backend solution is specific for every technology stack so I can't give a universal solution here. General idea is the following:
1) Parse the message in "on_message" function to find the requested "method name"
2) If the method is "set-channel" -> set the "self.channel" to this value
3) Broadcast further messages to subscribers with the same channel (I'm using Redis for that, but it also depends on your platform)
Hope it helps!

Resources