I'm having trouble with getting around asynchronous model of node, I have this function:
function getstream() {
console.log('calling testAvail, Avail value is:' + available);
testAvailability();
console.log('Available:'+available);
if (available || SelfSharing) {
// Do something
setDefaults();
return;
}
}
Which calls testAvailability() function defined as:
function testAvailability()
{
console.log('entered test');
var stat;
var socket = io.connect('http://somedomain.com');
socket.on('error', function() {
console.log('There was an error at server end please try again');
// chrome.runtime.reload();
setTimeout(chrome.runtime.reload(),3000);
//here i change options
//socket = io.connect(host, options);
});
socket.emit('available');
socket.on('available', function (status) {
console.log('got status from server which is:'+ status);
available=status;
console.log("inside the socket.on"+available);
console.log('leaving test, do you see any got status above?');
});
}
I want getstream() to continue from where it left after testAvailability() is done and available variable has it's value set.
You need to pass a callback to testAvailability and then call it inside socket's available event:
function testAvailability(callback)
{
console.log('entered test');
var stat;
var socket = io.connect('http://somedomain.com');
socket.on('error', function() {
console.log('There was an error at server end please try again');
// chrome.runtime.reload();
setTimeout(chrome.runtime.reload(),3000);
//here i change options
//socket = io.connect(host, options);
});
socket.emit('available');
socket.on('available', function (status) {
console.log('got status from server which is:'+ status);
available=status;
console.log("inside the socket.on"+available);
console.log('leaving test, do you see any got status above?');
callback(); <-- CALL YOUR CALLBACK FUNCTION HERE
});
}
Then change your getstream function so that it passes a callback to testAvailability and move the rest of the function inside that callback:
function getstream() {
console.log('calling testAvail, Avail value is:' + available);
testAvailability(function() {
console.log('Available:'+available);
if (available || SelfSharing) {
// Do something
setDefaults();
}
});
}
A couple of things to note:
getstream is now asynchronous. If something else is waiting for it to complete, you'll need to change it so that it takes a callback function as well.
I see that you're doing some sort of retry in socket's error event. That might be ok in this case, it depends on your app but, typically, you'll want to pass the error back as the first parameter of the callback when an error occurs.
Here we go:
function getstream() {
console.log('calling testAvail, Avail value is:' + available);
testAvailability(function(available){
console.log('Available:'+available);
if (available || SelfSharing) {
// Do something
setDefaults();
return;
}
});
}
function testAvailability(callback) {
console.log('entered test');
var stat;
var socket = io.connect('http://somedomain.com');
socket.on('error', function() {
console.log('There was an error at server end please try again');
// chrome.runtime.reload();
setTimeout(chrome.runtime.reload(),3000);
//here i change options
//socket = io.connect(host, options);
callback(false);
});
socket.emit('available');
socket.on('available', function (status) {
console.log('got status from server which is:'+ status);
console.log('leaving test, do you see any got status above?');
callback(true);
});
}
Related
I have a weird problem where my callback is never published and the message goes to timeout, even though the method runs in the queue. This happens in some specific queues and after it happens once, i cannot make any other requests from client which even previously worked, they all timeout. Have to restart the client and sever to make it working again.
This is the code, where its happening, and i cant seem to understand whats wrong.
Server.js file where i am creating the queues. I have several such queues, this is one of them.
var amqp = require('amqp');
var util = require('util');
var cnn = amqp.createConnection({host:'127.0.0.1'});
var getCart = require('./services/getCart');
cnn.on('ready', function() {
cnn.queue('getCart_queue', function(q){
q.subscribe(function(message, headers, deliveryInfo, m){
// util.log(util.format( deliveryInfo.routingKey, message));
// util.log("Message: "+JSON.stringify(message));
// util.log("DeliveryInfo: "+JSON.stringify(deliveryInfo));
getCart.handle_request(message, function(err,res){
cnn.publish(m.replyTo, res, {
contentType:'application/json',
contentEncoding:'utf-8',
correlationId:m.correlationId
});
});
});
});
});
Here, the handle request function is completed successfully, but the callback never goes through and its always timeout on the other end
var cart = require('../models/cart');
function handle_request(msg, callback) {
var user_id = msg.id;
cart
.find({id:user_id})
.populate('users ads')
.exec(function(err, results){
// This works, just the callback doesnt
if(!err){
console.log(results);
callback(null, results);
} else {
console.log(err);
callback(err, null);
}
});
}
exports.handle_request = handle_request;
this is how i am calling the request
var msg_payload = {"id":id};
mq_client.make_request('getCart_queue', msg_payload, function(err, results){
console.log(results); // never prints
//stuff that is never reached
});
These are my rpc files, i dont think there should be anything wrong with these, as some other queues work fine.
And this is the error shown on client
GET /getCart - - ms - -
Error: timeout 6ee0bd2a4b2ba1d8286e068b0f674d8f
at Timeout.<anonymous> (E:\Ebay_client\rpc\amqprpc.js:32:18)
at Timeout.ontimeout [as _onTimeout] (timers.js:341:34)
at tryOnTimeout (timers.js:232:11)
at Timer.listOnTimeout (timers.js:202:5)
Hope the information is not vague, if you need more, please let me know. Thanks!
I Think the error is in this file, because i tried debugging and from the rabbitmq server, the callback is being called and it has the correlation id as well as the reply to variable, so the request is not getting picked up here.
var amqp = require('amqp')
, crypto = require('crypto');
var TIMEOUT=8000;
var CONTENT_TYPE='application/json';
var CONTENT_ENCODING='utf-8';
var self;
exports = module.exports = AmqpRpc;
function AmqpRpc(connection){
self = this;
this.connection = connection;
this.requests = {};
this.response_queue = false;
}
AmqpRpc.prototype.makeRequest = function(queue_name, content, callback){
self = this;
var correlationId = crypto.randomBytes(16).toString('hex');
var tId = setTimeout(function(corr_id){
callback(new Error("timeout " + corr_id));
delete self.requests[corr_id];
}, TIMEOUT, correlationId);
var entry = {
callback:callback,
timeout: tId
};
self.requests[correlationId]=entry;
self.setupResponseQueue(function(){
self.connection.publish(queue_name, content, {
correlationId:correlationId,
contentType:CONTENT_TYPE,
contentEncoding:CONTENT_ENCODING,
replyTo:self.response_queue});
});
};
AmqpRpc.prototype.setupResponseQueue = function(next){
if(this.response_queue) return next();
self = this;
self.connection.queue('', {exclusive:true}, function(q){
self.response_queue = q.name;
q.subscribe(function(message, headers, deliveryInfo, m){
var correlationId = m.correlationId;
if(correlationId in self.requests){
var entry = self.requests[correlationId];
clearTimeout(entry.timeout);
delete self.requests[correlationId];
entry.callback(null, message);
}
});
return next();
});
};
This is the code for your make_request() in client.js file:
var amqp = require('amqp');
var connection = amqp.createConnection({host:'127.0.0.1'});
var rpc = new (require('./amqprpc'))(connection);
function make_request(queue_name, msg_payload, callback){
rpc.makeRequest(queue_name, msg_payload, function(err, response){
if(err)
console.error(err);
else{
console.log("response", response);
callback(null, response);
}
});
}
exports.make_request = make_request;
Look at what happens when you have an err on rpc.makeRequest():
rpc.makeRequest(queue_name, msg_payload, function(err, response){
if(err)
console.error(err);
//
//HERE: should be a callback call here.
//
else{
console.log("response", response);
callback(null, response);
}
});
This could be why you are getting a timeout. I hope it helps.
There wasn't a problem with rabbitMQ but with my queries in the handle request and after responding to the request.
For others coming with this problem, check and double check every statement, as the error will not show in the console, but will only show a timeout
I attached my server code:
var net = require('net');
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('MyBBDD.db');
var prueba = '';
function get_kw_actual(nombre,callback){
stmt = db.prepare("SELECT kw_actual FROM usuarios WHERE usuario = ?");
stmt.bind(nombre);
stmt.get(function(error,row){
if(error){
throw err;
}
else{
if(row){
entero=row.kw_actual;
callback(entero);
}
else{
console.log("error");
}
}
});
}
var server = net.createServer(function(socket) {
console.log("Recibo peticion");
socket.on('data', function (data) {
get_kw_actual('Pepe',function(resultado){
console.log('resultado es: ' + resultado);
prueba = '' + resultado;
})
socket.write(prueba);
});
socket.on('close', function () {
console.log('Connection closed');
});
});
server.listen(1337, '192.168.1.101');
In my server, I receive a request, I call to my function "get_kw_actual" I get a number of my database and finally I respond with the result.
The problem is that it runs first "socket.write(prueba);" than:
stmt.get(function(error,row){
if(error){
throw err;
}
else{
if(row){
entero=row.kw_actual;
callback(entero);
}
else{
console.log("error");
}
}
});
So... the execution is not executed in the correct order and the result is not correct.
Somebody know how can I solve it?
Thanks in advance.
Best regards.
Node.js code runs asynchronously. The code in the callback get_kw_actual returns immediately but the callback will run at some later time, when the database operation has completed. What you want to do is put socket.write inside of the callback, like this:
socket.on('data', function (data) {
get_kw_actual('Pepe',function(resultado){
console.log('resultado es: ' + resultado);
socket.write(resultado);
})
});
Also note that you're using a global variable prueba in your code, which will get clobbered when you have multiple clients running against your server. Do not use global variables like this in node.
I have a requirement that i want to run my task after booting a http server.
But i cannot check whether the server is booted.
Instead,i used a setTimeout function to assume the server is booted with 2 seconds interval.
Could anybody,who knows a better solution,help me?
Great thanks!
My code is as follows:
// main.js
function exec(command) {
var defer = q.defer();
var child = childProcess.exec(command, function (err, stdout, stderr) {
if (err) {
return defer.reject(err);
}
});
child.stdout.pipe(process.stdout);
// TODO: find another graceful way to check child process ends
setTimeout(function () {
defer.resolve();
}, 2000);
return defer.promise;
}
exec('"' + process.execPath + '" app.js')
.then(function () {
// my task here;
console.log('my task')
});
// app.js
var http = require('http'),
server;
server = http.createServer(function (req, res) {
// serve html;
res.end('hello world');
});
server.listen(9999);
// run
$> node main.js
A good solution would be to try to connect to the webserver until it responds. Since you're using Q, you can take a look at the code from this answer, which enables you to retry an operation until it succeeds.
function retry(operation, delay) {
return operation().catch(function(reason) {
// Note: I replaced delay * 2 by delay, it will be better in your case
return Q.delay(delay).then(retry.bind(null, operation, delay));
});
}
Then you could do something like
startMyWebServer()
.then (function () {
return retry(connectToWebServer, 500).timeout(10000);
})
.then(function () {
console.log("Webserver ready")
})
.catch(function (err) {
console.log("Unable to contact webserver")
});
The call to retry will retry to connect to the webserver if the previous connection failed, with a delay of 500ms. If after 10s it didn't succeed, the promise will be rejected.
The connectToWebServer function should be a function that tries to connect to your webserver and returns a promise, i.e. something like
function connectToWebServer() {
var d = q.defer();
request('http://your-ip:your-port', function (err, res) {
if (err || res.statusCode != 200) {
return d.reject("Error : "+(err || "status code "+res.statusCode));
}
d.resolve();
}
return d.promise;
}
I am using the SerialPorts module for nodejs and need to be able to open, write and read from a variable number of serial ports.
So what I am doing is to first create an array object for the serialPort instances, and then process them in a loop:
var serialport = require("serialport");
var SerialPort = serialport.SerialPort; // localize object constructor
var devs = ["/dev/tty.SerialPort","/dev/tty.HHW-SPP-1800-2-DevB"];
var ports = [];
for (var i = 0; i < devs.length; i++) {
console.log(devs[i]);
var port = new SerialPort(devs[i],{ baudrate:9600, parser: serialport.parsers.readline("\n") });
ports.push(port);
}
Then I have another function that I call periodically to read / write from the ports:
function minute(){
for (var i = 0; i < ports.length; i++) {
console.log(i);
ports[i].on("open", function (path) {
console.log('opened');
ports[i].write("Helo World\n", function(err,res) {
if(err) console.log('err ' + err);
console.log('results ' + res);
});
ports[i].on("data", function (data) {
console.log("here: "+data);
});
});
}
}
The problem is the minute() function executes, however it does not attempt to open or read / write to the ports.
What am I doing wrong ?? and is there a better way of doing this ??
There are a couple misconceptions at play here.
Firstly, you don't need to periodically poll your ports. Nodejs uses an event loop (more or less), to handle IO, and will do the polling for you. So all you need to do is setup the callbacks for the open event, one time for each port. In your code, it looks like you are readding the callback each time minute() is being called. That is not necessary.
Secondly, javascript doesn't have block scoping for variables. Instead you are inadvertently creating a closure, and your code is in error. In this following block:
for (var i = 0; i < ports.length; i++) {
ports[i].on("open", function (path) {
ports[i].write("Helo World\n", function(err,res) {
if(err) console.log('err ' + err);
console.log('results ' + res);
});
ports[i].on("data", function (data) {
console.log("here: "+data);
});
});
}
When your callback for ports.on is invoked, the value of i in ports[i].write and ports[i].on("data") isn't the value of i when the callback is setup, as you are expecting. Instead, because you have created a closure, the value of i isn't bound(set) until the callback is executed. In this example, everyone of your callbacks, i will be set to ports.length, which was the last evaluated value for i
I've created a plunkr that illustrates the problem with your for loop.
One way to fix this problem is to use an anonymous method, and bind the value i to a new local variable. In the code below, (function(index){})(i); executes immediately, and binds the value index to the appropriate value of i.
ports[i].on("open", function (path) {
(function(index) {
ports[index].write("Helo World\n", function(err,res) {
if(err) console.log('err ' + err);
console.log('results ' + res);
});
ports[index].on("data", function (data) {
console.log("here: "+data);
});
})(i);
});
You could also instead pull that method out into a separate function. setupHandlers() executes immediately, and is bound to the proper port.
for (var i = 0; i < ports.length; i++) {
setupHandlers(ports[i]);
}
function setupHandlers(port) {
port.on("open", function (path) {
ports.write("Helo World\n", function(err,res) {
if(err) console.log('err ' + err);
console.log('results ' + res);
});
ports.on("data", function (data) {
console.log("here: "+data);
});
});
}
I have a main in nodejs for my program where I need to use my result calculated in a module, but my I don't have the right result.
var myJSONClient = {
"nombre" : "<nombre_cliente>",
"intervalo" : [0,0]
};
var intervalo = gestionar.gestion(myJSONClient,vector_intervalo);
console.log("intervalo: "+intervalo); //return undefined
And this is the module
var gestion = function(myJSON,vector_intervalo) {
var dburl = 'localhost/mongoapp';
var collection = ['clientes'];
var db = require('mongojs').connect(dburl, collection );
var intervalo_final;
function cliente(nombre, intervalo){
this.nombre = nombre;
this.intervalo = intervalo;
}
var cliente1 = new cliente(myJSON.nombre,myJSON.intervalo);
db.clientes.save(cliente1, function(err, saveCliente){
if (err || !saveCliente) console.log("Client "+cliente1.nombre+" not saved Error: "+err);
else {
console.log("Client "+saveCliente.nombre+" saved");
intervalo_final = calculate(vector_intervalo);
console.log(intervalo_final); //here I can see the right content of the variable intervalo_final
}
});
setTimeout(function(){
console.log("pause");
},3000);
console.log(intervalo_final); //result not correct
return intervalo_final;
}
exports.gestion = gestion;
I know that node execute my return without wait the end of my function, for this I can't see the right result, but how can I force my program to wait the end of my function?
I tried with the setTimeout function but wasn't the right way.
You must implement your function just like the other async functions from the API!
First step : give callback to function
var gestion = function(myJSON,vector_intervalo, callback) {
Second step : when the async process is over call callback passing the result (you don't need the return line)
console.log(intervalo_final); //here I can see...
callback(intervalo_final);
Step three: use your function in an async way
gestionar.gestion(myJSONClient,vector_intervalo, function(result){
console.log(result);
});
In async JS you can't return a value the way it seems you trying to do. You need to pass a callback function from your main program when calling gestionar.gestion() (you can add it as a third argument).
Your code sample won't work because function gestion() returns immediately, before intervalo_final content is set.
Something like this:
gestionar.gestion(myJSONClient,vector_intervalo, function callback(intervalo) {
// This is the callback function
console.log("intervalo: " + intervalo);
});
And then within the function:
var gestion = function(myJSON,vector_intervalo, callback) {
...
db.clientes.save(cliente1, function(err, saveCliente) {
if (err || !saveCliente) {
console.log("Client "+cliente1.nombre+" not saved Error: "+err);
if (callback) callback(); // execute callback function without arguments
}
else {
console.log("Client "+saveCliente.nombre+" saved");
intervalo_final = calculate(vector_intervalo);
console.log(intervalo_final);
if (callback) callback(intervalo_final); // your callback function will be executed with intervalo_final as argument
}
});
Also, I highly recommend reading some async javascript tutorial, like http://javascriptissexy.com/understand-javascript-callback-functions-and-use-them/
And Felix's Node.js Guide: http://nodeguide.com/