Azure IOT Hub MQTT Messages Lost on Internet drop - azure

We are using azure-iot-device-mqtt node package to connect a debian computer to the Azure IOT Hub. We have noticed that when the Internet drops (i.e. we disconnect it) Device Explorer thinks the device is still connected (for about 10 seconds) and messages being fired in this period do not reach the device (or get queued). After 10 seconds they appear in the Device Explorer queue. Also the device still thinks it's connected and does not recover the connection.
We have tried package versions 1.1.17 and 1.2.1 and have the same symptoms on both.
var clientFromConnectionString = require('azure-iot-device-mqtt').clientFromConnectionString;
var Message = require('azure-iot-device').Message;
var connectionString = 'xxx';
var client = clientFromConnectionString(connectionString);
var connectCallback = function (err) {
if (err) {
console.error('Could not connect: ' + err);
} else {
console.log('Client connected');
var message = new Message('some data from my device');
client.sendEvent(message, function (err) {
if (err) console.log(err.toString());
});
client.on('message', function (msg) {
console.log(msg);
client.complete(msg, function () {
console.log('completed');
});
});
client.on('disconnect', function () {
console.log("disconnect");
});
}
};
client.open(connectCallback);
N.b We require MQTT as we are using direct-method functionality.
With the AMQP package as soon as any disconnection the messages from the cloud instantly go into the queue.
Summary of issues:
MQTT messages lost for first 10-15 seconds of disconnection (After this they are queued cloud side).
MQTT+AMQP clients does not detect disconnects.
Any advice would be greatly appreciated.
Thanks,
David

Related

How to close a Node.js UDP (dgram) socket

The App crashes if I do not call client.close in the program below.
The send of message and receiving of data works fine. But if I exit the function and comes back to it again later, the App crashes and I can not receive message anymore. I restart the Smart Phone and it works again only for the first time the function runs.
If I put client.close() inside the client.on('message',, I only get the first data from the host or source, because the socket will close prematurely. Also the App do not crash.
If I remove the client.close(), I get all the data from multiple sources saved in the array I provided let RawMessageUDP = [].
Also I confirmed that the callback function of the client.on('message', will not be executed when there are no more message in the socket.
How can I determine that there are no more message in the socket, so I can close it?
There are two hosts which receives the message and reply data string back to this App. There are no issues in the host I confirmed since they close the connection after sending.
Send_UDP_Multicast = async () => {
const message = Buffer.from('Some bytes');
const client = dgram.createSocket('udp4');
let RawMessageUDP = []
let countMessage = 0
client.on('error', (err) => {
console.log(err.stack)
client.close()
})
client.on('message', (data, rinfo) => { //Console: socket-x, bound to address: 0.0.0.0, port: 65000 max
RawMessageUDP[countMessage] = data.toString()
console.log('Receiving remote data.' + RawMessageUDP[countMessage])
countMessage++
//client.close()
})
client.send(message, 0, message.length, 1900, '239.255.255.250', (err) => {
if (err) {
console.log(err);
client.close();
}
})
}
https://github.com/jurniores/SocketUDP resolve your problem. This lib you will find how to disconnect the clients and if the clients fall down it will disconnect them and will not overload your server.

How can I deal with message processing failures in Node.js using MQTT?

I'm using a service written in Node.js to receive messages via MQTT (https://www.npmjs.com/package/mqtt) which then writes to a database (SQL Server using mssql).
This will work very nicely when everything is functioning normally, I create the mqtt listener and subscribe to new message events.
However, if the connection to the DB fails (this may happen periodically due to a network outage etc.), writing the message to the database will fail and the message will be dropped on the floor.
I would like to tell the MQTT broker - "I couldn't process the message, keep it in the buffer until I can."
var mqtt = require('mqtt')
var client = mqtt.connect('mymqttbroker')
client.on('connect', function () {
client.subscribe('messagequeue')
})
client.on('message', function (topic, message) {
writeMessageToDB(message).then((result) => {console.log('success'};).catch((err) => {/* What can I do here ?*/});
})
Maybe set a timeout on a resend function? Probably should be improved to only try n times before dropping the message, but it's definitely a way to do it. This isn't tested, obviously, but it should hopefully give you some ideas...
var resend = function(message){
writeMessageToDB(message).then((result) => {
console.log('Resend success!')
})
.catch((err) => {
setTimeout(function(message){
resend(message);
}, 60000);
});
}
client.on('message', function (topic, message) {
writeMessageToDB(message).then((result) => {
console.log('success')
})
.catch((err) => {
resend(message);
});
});

Mosca sends multiple messages continously

I have setup a node js server with Mosca running on it. Clients are able to connect to the Mosca server and publish a message. I need to the send an acknowledgment in the form of a message(subscribed to some topic) back to the client.
The below code sends multiple messages continuously once the message is published by the client. Am I missing anything?
var settings = {
port: 1882,
backend: ascoltatore
};
var message = {
topic: 'crofters',
payload: 'OK', // or a Buffer
qos: 2
};
var server = new mosca.Server(settings);
server.on('clientConnected', function(client) {
console.log('client connected', client.id);
});
// fired when a message is received
server.on('published', function(packet, client ) {
var packet_payload = packet.payload;
packet_payload = packet_payload.toString();
console.log('Published', packet_payload);
server.publish(message, function() {
console.log('done!');
});
});
server.on('ready', setup);
function setup() {
console.log('Mosca server is up and running');
}
The event listener server.on('published', function(packet, client){...} listens to every publishing events, including the server's.
What is happening is that when you use server.publish(message, function(){...}) inside that listener it triggers another published event, which is immediately caught by the listener.
It never stops publishing because it never stops catching its own events.
I have been facing similar issues. If you notice, Mosca has only QoS 0 and Qos 1
So I suppose the broker tries to send the same message more than once "at least once" until it receives some acknowledgement from a client. Check this document out

Publisher and subscriber not working in negative scenarios

Hi I am using zeroMQ for my node application where i use the publisher and subscriber for message queuing.Below is my code
Publisher.js
var zmq = require('zmq')
var publisher = zmq.socket('pub')
publisher.bind('tcp://127.0.0.1:7000', function(err) {
if(err)
console.log(err)
else
console.log("Listening on 7000...")
})
setTimeout(function() {
console.log('sent');
publisher.send("hi")
}, 1000)
process.on('SIGINT', function() {
publisher.close()
console.log('\nClosed')
})
Subscriber.js
var zmq = require('zmq')
var subscriber = zmq.socket('sub')
subscriber.on("message", function(reply) {
console.log('Received message: ', reply.toString());
})
subscriber.connect("tcp://localhost:7000")
subscriber.subscribe("")
process.on('SIGINT', function() {
subscriber.close()
console.log('\nClosed')
})
The above code is working fine if both the publisher and subscriber are running.If i stop my subscriber i'm not able to receive the publisher's data when the subscriber is offline.I want to persist the data even if my subscriber is down.I'm stuck here.Any help will be much appreciated.
See the 'Last value caching' pattern on zmq docs site. You can extend the example with the client first subscribing to a pattern with the latest item it had received, and the lvc proxy to resend the missing values(it has to cache them first). But this might work for a small number of cached items where disconnects happen rarely, otherwise PUSH might be the better option. PUB-SUB is not intended to support buffering.

APN Feedback service does not send tokens

I implemented a node.js script that queries the APN Feedback service to retrieve the list of invalid tokens. Unfortunately, I did not manage to get any invalid token. I followed these steps:
Install the ios app with push notifications in sandbox mode.
Send some notifications to the app (done successfully).
Uninstall the app (I read that if the app that I uninstall is the only one with push notifications, it will cause the disconnection from the APN Service and make impossible to notify it that the app was uninstalled; but this is not my case, the iPad has many push notification apps installed!!).
Send many other notifications with the same token, about ten or twenty, just to prove that the application token is not valid anymore (obviously the notifications are not delivered because the app has just been uninstalled).
Query the Feedback service to finally get the invalid token. The
Feedback service does not send anything, it just closes the connection without any kind of data.
This is the script I use to query the feedback service:
function pollAPNFeedback() {
var certPem = fs.readFileSync('apns-prod-cert.pem', encoding='ascii');
var keyPem = fs.readFileSync('apns-prod-key-noenc.pem', encoding='ascii');
var options = { key: keyPem, cert: certPem };
console.log("Connecting APN feedback service");
var stream = tls.connect(2196, 'feedback.sandbox.push.apple.com', options, function() {
if (stream.authorized == false) {
return console.log('not connected')
} else {
console.log('connected');
};
var bufferlist = [];
stream.on('data', function(data) {
// APN feedback starts sending data immediately on successful connect
console.log('-->Data: ', data);
//bufferlist.push(data);
});
stream.on('readable', function(){
console.log('we have incoming data');
});
stream.on('error', function(err){
console.log('error: ', err);
});
stream.on('close', function(){
console.log('closed');
console.log('stream.data = ', stream.data);
});
});
}
As you can see, I put some listeners on the stream variable. The callback function on the 'data' listener is never invoked, only the 'close' event triggers its callback. I am sure that the connection is up because stream.authorized is true.
What am I doing wrong?
Is it possible that you are using a production certificate to contact the sandbox environment?
From your code :
var certPem = fs.readFileSync('apns-prod-cert.pem', encoding='ascii');
var keyPem = fs.readFileSync('apns-prod-key-noenc.pem', encoding='ascii');
And :
var stream = tls.connect(2196, 'feedback.sandbox.push.apple.com', options, function()
If that's the case, that's why it doesn't work.

Resources