zeromq push-pull guaranteed delivery (re-transmit on error) - javascript

How can I fail a PULL to get retransmit from the pusher?
In the following example, if I uncomment the // throw ... to trigger an exception on every received message, all the PULL messages are failing, but when I put back the comment, all those messages are lost and not retransmitted by the pusher.
How can I make sure the pusher will retransmit the messages if the PULL method fail?
P.S. The following code is JavaScript in Meteor framework on top of nodejs, but it's not relevant to the problem as I suppose it's similar in every zmq implementations.
var zmq = Npm.require(modulePath + '/zmq');
var sock = zmq.socket('pull');
sock.identity = 'receiving' + process.pid;
sock.bind('tcp://172.17.4.25:5551', function(err) {
if (err) throw err
if (debug) console.log('Listening for ZMQ messages')
});
sock.on('message', Meteor.bindEnvironment(function(data) {
// throw { name: 'MessagePullFailed', message: 'Failing Pull message to check if ZMQ can recover from it' }
var jsondata = JSON.parse(data)
if (jsondata.cmd == 'upsert') {
jsondata['set']['utctime'] = new Date(jsondata['set']['utctime'])
Mon.upsert({_id: jsondata._id}, {'$set': jsondata['set']}, function(err) {
if (err) console.log(err)
})
}
}))

Related

how to reply and send message after receive message in node js using websocket

After receive message from client, I have to connect db(mysql) and save data and need to response the result to client and inform to other(admin) client.
So I need to get current socket client and special client(admin) from the socket list.
Is it possible to get current socket outside of wss connection block?
Thanks.
const WebSocketServer = require('ws');
// Creating a new websocket server
const wss = new WebSocketServer.Server({ port: 8080 });
const clients = new Map();
// Creating connection using websocket
wss.on("connection", ws => {
console.log("new client connected");
client_id = Date.now();
clients.set(client_id, ws);
// sending message
ws.on('message', function(message) {
//wss.broadcast(JSON.stringify(message));
console.log('Received: ' + message);
BuyCoin(message);
//console.log()
});
ws.on("close", () => {
console.log("the client has connected");
});
ws.onerror = function () {
console.log("Some Error occurred")
}
// ws.send('You successfully connected to the websocket.');
});
function BuyCoin(strValue){
const req_info = JSON.parse(strValue);
console.log(req_info.user_id)
console.log('betting!');
var sql = 'SELECT * from users where id = ? LIMIT 1'
connection.query(sql, req_info.user_id, (ws)=>{
return function(err, rows, fields) {
//console.log("ix="+ix);
ws.send(rows[0]);
};
});
}
}
You have several options:
#1: You can put the BuyCoin function logic inside the ws scope to make it a local function that is in scope of the ws variable for the current connection like this:
const WebSocketServer = require('ws');
// Creating a new websocket server
const wss = new WebSocketServer.Server({ port: 8080 });
const clients = new Map();
// Creating connection using websocket
wss.on("connection", ws => {
console.log("new client connected");
client_id = Date.now();
clients.set(client_id, ws);
// sending message
function BuyCoin(strValue) {
const req_info = JSON.parse(strValue);
console.log(req_info.user_id)
console.log('betting!');
var sql = 'SELECT * from users where id = ? LIMIT 1'
connection.query(sql, req_info.user_id, (ws) => {
return function(err, rows, fields) {
//console.log("ix="+ix);
ws.send(rows[0]);
};
});
}
ws.on('message', function(message) {
//wss.broadcast(JSON.stringify(message));
console.log('Received: ' + message);
BuyCoin(message);
//console.log()
});
ws.on("close", () => {
console.log("the client has connected");
});
ws.onerror = function() {
console.log("Some Error occurred")
}
// ws.send('You successfully connected to the websocket.');
});
#2: You can pass the ws value to your BuyCoin() function as an argument by just changing the function call from this:
BuyCoin(message);
to this:
BuyCoin(ws, message);
And, then changing your function declaration from this:
function BuyCoin(strValue) {...}
to this:
function BuyCoin(ws, strValue) {...}
Is it possible to get current socket outside of wss connection block?
No, there really is no such thing as the current socket. When using asynchronous code in nodejs, lots of different pieces of code can be "in-flight" at the same time so there is no global sense of the current socket. Instead, you have manage data specific to your current operation either by using scope, by passing as an argument or by setting as a properties on some other object that is passed as an argument. Since there is no natural object that BuyCoin() already has access to here that is specific to the user with the activity, then that leaves the first two options (using scope and passing as an argument).
FYI, this code looks a bit problematic because you're allowing the webSocket to send in the user_id that will be operated on without any visible authentication. That exposes you to rogue sockets that can pretend to be users that they aren't.
Also, it doesn't appear you have code that removes webSockets from the clients Map object when they disconnect so that Map object will just get larger and larger and contain lots of dead connections.
Another thing that needs fixing is that your connection.query() code is declaring a callback that does nothing but return another function and it tried to make up a value of ws that would never actually be passed. That function you create inside the callback is never called. Change from this:
connection.query(sql, req_info.user_id, (ws) => {
return function(err, rows, fields) {
//console.log("ix="+ix);
ws.send(rows[0]);
};
});
to this:
connection.query(sql, req_info.user_id, (err, rows, fields) => {
//console.log("ix="+ix);
ws.send(rows[0]);
});
And, combine that with one of the above two solutions to get access to the ws value.

How to properly end a MongoDB client connection on error?

I have a MongoDB instance and two JavaScript services running on a Linux server. The first service, moscaService.js, listens to MQTT topics on the server, and records what is sent in a MongoDB collection. The second service, integrationService.js, runs every second, reading data on the same MongoDB collection and, if there's a new register (or more), sends it to Ubidots.
The problem is that both services work on the same IP/port: localhost:27017; and, if there ever is an occasion in which both of them are active simultaneously (say, moscaService.js is recording something and then the integrationService.js tries to connect), there will be a connection error and the service will restart.
Here are the connection parts of both services:
var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://127.0.0.1:27017/myGateway';
//integrationService.js
var job1 = new CronJob('*/1 * * * * *', function() {
MongoClient.connect(url, function(err, db) {
if(err != null) {
logger.error({message: 'Connection error: ' + err});
process.exit(0);
} else {
executeService();
}
function executeService() {
// execution block
}
});
}, null, true, timeZone);
//moscaService.js
server.on('published', function(packet, client) {
//the packet is read here
MongoClient.connect(url, function(err, db) {
if(err != null) {
logger.error({message: 'Connection error: ' + err});
process.exit(0);
} else {
executeService();
}
function executeService() {
// execution block
}
});
});
What I need is a way to properly handle the err instead of just exiting the service, because if there are new messages being published while the service is restarting, they will be lost. Something like testing if the port is open before connecting, or open a different port.
I tried creating another instance of MongoDB on a different port, in order to have each service listen to one, but it looks like Mongo locks more than one instance if it's trying to connect to the same database.
The code snippets here are just a small part; if anyone needs more parts to answer, just say so and I'll add them.
I have made an alteration and it solved this issue. I altered the code in a way that integrationService connects to MongoDB before starting the CronJob; that way, it only connects once and it keeps the connection alive.
Here's the connection part of the code:
var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://127.0.0.1:27017/myGateway';
//integrationService.js
MongoClient.connect(url, function(err, db) {
var job1 = new CronJob('*/1 * * * * *', function() {
if(err != null) {
logger.error({message: 'Connection error: ' + err});
process.exit(0);
} else {
executeService();
}
function executeService() {
// execution block
}
}, null, true, timeZone); // end CronJob
}); // end MongoClient.connect
Since this has solved the problem, I've left the err treatment as is was (although a more elegant way to treat it is still desirable).
Solving the problem on integrationService has solved it on moscaService as well, but I plan to make the same alteration on the second service too.

Update properties of a model

I am trying to implement a feature where I can press on a button to delete some properties of my model.
My Model is:
Request:
status
shopper
I am using an event based structure:
This is the front end
a.requests-deny(href='#', data-id=request.id) Deny request
and this is my backend
var Request = require('../../models/Request');
var ShopperRequests = Backbone.View.extend({
el: '.shoppers-requests',
events: {
'click .requests-deny' : 'requestDeny'
},
requestDeny: function(e){
e.preventDefault();
var target = $(e.currentTarget);
var requestId = target.data('id');
console.log(requestId);
Request.findById(requestId, function(err, request) {
console.log(request);
if (err) {
return console.log('oh no! error', err);
} else {
request.status = 'pending';
request.shopper = '';
request.save(function(err) { // <-- save it back to the database
if (err) {
console.log('oh no! could not be saved in db', err);
} else {
console.log(request);
}
});
}
});
},
Looking at the console in the browser I see that first of all I can't use "require" because "it's not defined"
Uncaught ReferenceError: require is not defined(anonymous function) # shopper-f28ac0daf1d6a206b3172e4b9c670dd4.js:1
I was thinking of taking the requestId and just updating the values in the database but apparently this is not working.
Any idea if this could work or how else I could implement it?
You are not loading the RequireJs library in your backend. Thats why you are getting require is not defined.
If you are using Node, add it like this:
npm install requirejs
Or else, download it from here, and add it to your project with a script tag.

Sending input data to child process in node.js

I am writing code to create an online c++ compiler in node.js environment.Using spawn function i created a child process which will compile the code and execute it and send the output back to the user.
But i need to send input to the running c++ program . I used child.stdin.write('data');
for sending data to child but i think cin in the program is not receiving the input .
Please help me to send the input to the running c++ code.
Thanks.
1.Create a file with input data.
2.Create a ReadStream opening input file.
3.Pipe the ReadStream with childprocess.stdin.
file=fs.createReadStream('input.txt',{encoding:'utf8'});
file.pipe(childprocess.stdin);
This worked for me .
You should probably use either cluster, or fork if you want to pass messages... if you do this, node will setup IPC for you to be able to communicate via process.send
Alternatively, you could use a pub/sub system for communication channels (Redis works well for this), this is also your best bet if you need communications across servers.
Below is an example of an older work script...
var env = process.env.NODE_ENV || 'dev';
var cluster = require("cluster");
//TODO: need to adjust to use domains for this work
process.on('uncaughtException', function (err) {
console.error('GENERAL EXCEPTION IN %s: %s', process.env.WORKER_TYPE || 'MASTER',err);
if (err.stack) console.error(err.stack);
if (cluster.isWorker) {
//process.send notifies the parent process of the error
process.send({
err: {
"str": err && err.toString() || "unknown error"
,"message": err && err.message || null
,"stack": err && err.stack || null
}
});
}
process.nextTick(function(){
process.exit(666);
});
});
if (cluster.isMaster) startMaster();
if (cluster.isWorker) startWorker();
function startMaster() {
createWorker("foo");
createWorker("bar");
}
function createWorker(workerType) {
var worker = cluster.fork({"WORKER_TYPE":workerType}); //passes environment variables to child
worker.on('online',onOnline.bind(null, worker));
worker.on('message',onMessage.bind(null, worker));
worker.on('exit',onExit.bind(null, worker));
worker.workerType = workerType;
return worker;
// you can use worker.send() to send a message that
// will raise a message event in the child
}
function startWorker() {
console.log("Running Worker: %s %s", cluster.worker.id, process.env.WORKER_TYPE);
setTimeout(process.exit.bind(process,0), 5000); //close in 5 seconds
//you may want to load a specific module based on WORKER_TYPE
}
function onOnline(worker) {
console.log("Worker Online: %s %s", worker.id, worker.workerType);
//console.log(arguments);
}
function onMessage(worker, msg) {
if (msg.err) {
console.warn("Error From", worker.id, worker.workerType, msg.err);
} else {
console.log("Message From", worker.id, worker.workerType);
}
//console.log(arguments);
}
function onExit(worker, code, signal) {
console.log("Worker Exited: %s %s %s %s", worker.id, worker.workerType, code, signal);
if (env == 'dev') {
//for now just exit the whole thing (dev mode)
process.nextTick(function(){
process.exit(1);
});
} else {
//workers should simply keep working...
//fire off a new worker
createWorker(worker.workerType);
}
}

phonegap app: Uncaught ReferenceError: require is not defined

I'm trying to connect to a remote database from my phonegap app.
I'm using an example script I found, but it's not working, as I keep getting require is not defined error.
Here's my code (it's inside a tag):
var Client = require('mysql').Client;
var client = new Client();
client.host ='1**.**.**.**8:****';
client.user = '*****';
client.password = '*****************';
console.log("connecting...");
client.connect(function(err, results) {
if (err) {
console.log("ERROR: " + err.message);
throw err;
}
console.log("connected.");
clientConnected(client);
});
clientConnected = function(client)
{
tableHasData(client);
}
tableHasData = function(client)
{
client.query(
'SELECT * FROM test_db.Users LIMIT 0,10',
// you can keep this function anonymous
function (err, results, fields) {
if (err) {
console.log("ERROR: " + err.message);
throw err;
}
console.log("Got "+results.length+" Rows:");
for(var i in results){
console.log(results[i]);
console.log('\n');
//console.log("The meta data about the columns:");
//console.log(fields);
}
client.end();
});
};
What am I doing wrong??
You are probably using nodeJS code that can't be run on Cordova. This must be run with node.
What you need to do is create a server (where you will run your code with nodeJS) and expose your data through an API for the client (your Cordova app) to come and fetch them. (Use AJAX requests)

Categories