I am playing with elasticsearch.js from the browser. I would like to ping elasticsearch, wait for the request to complete and then return the result of the connection. But right now it is happening asynchronously, and returning undefined even when the connection is ok. I have code like this:
var connectionOK = false;
function createElasticsearchClient(hostAddress) {
var client = new $.es.Client({
hosts: hostAddress
});
return client;
}
function checkElasticsearchConnection(client) {
$.when(pingElasticsearch(client)).done(function () {
return connectionOK;
});
}
function pingElasticsearch(client) {
console.log("ELASTICSEARCH: Trying to ping es");
client.ping({
requestTimeout: 30000,
// undocumented params are appended to the query string
hello: "elasticsearch"
}, function (error) {
if (error) {
console.error('ELASTICSEARCH: Cluster is down!');
connectionOK = false;
console.log("INSIDE: " + connectionOK);
} else {
console.log('ELASTICSEARCH: OK');
connectionOK = true;
console.log("INSIDE: " + connectionOK);
}
});
}
and how it is used:
var esClient = createElasticsearchClient("exampleserver.com:9200");
var esCanConnect = (checkElasticsearchConnection(esClient));
You're mixing asynchronous functions with synchronous functions. You could go with this approach instead:
function createElasticsearchClient(hostAddress, callback) {
var client = new $.es.Client({
hosts: hostAddress
});
return callback(client);
}
function pingElasticsearch(client, callback) {
console.log("ELASTICSEARCH: Trying to ping es");
client.ping({
requestTimeout: 30000,
// undocumented params are appended to the query string
hello: "elasticsearch"
}, function (error) {
if (error) {
return callback('ELASTICSEARCH: Cluster is down!');
} else {
return callback(null);
}
});
}
And then run
createElasticsearchClient("exampleserver.com:9200", function(esClient) {
pingElasticsearch(esClient, function(err) {
if (err) console.log(err);
else {
//Everything is ok
console.log('All good');
}
});
});
Related
I have the Problem that the return is made before methodStatus is set to true (so the return is always false even when I can see 'success' in the console log)
function anmelden(username, userPassword){
var methodStatus = false;
var opts = {
filter: 'sAMAccountName=' + username,
scope: 'sub'
};
ldapClient.search('OU=secret,OU=secret,DC=secret,DC=secret', opts, function(err, res) {
res.on('searchEntry', function(entry) {
var userClient = ldap.createClient({url: 'ldap://secret:1111'});
userClient.bind(entry.object.dn + '', userPassword, function(err) {
if(err) {
console.log('failed')
methodStatus = false;
} else {
console.log('success')
methodStatus = true;
}
ldapBind();
});
});
console.log('end');
return methodStatus;
});
}
This is the console log:
end
success
Thank you for your help :)
it is because of asynchrony. the return is invoked before the callback of the res.on is invoked. there are a lot of ways to handle it, for example to add a callback to the anmelden and to invoke it when the work is done:
function anmelden(username, userPassword, callback){
var methodStatus = false;
var opts = {
filter: 'sAMAccountName=' + username,
scope: 'sub'
};
ldapClient.search('OU=secret,OU=secret,DC=secret,DC=secret', opts, function(err, res) {
res.on('searchEntry', function(entry) {
var userClient = ldap.createClient({url: 'ldap://secret:1111'});
userClient.bind(entry.object.dn + '', userPassword, function(err) {
if(err) {
console.log('failed')
methodStatus = false;
} else {
console.log('success')
methodStatus = true;
}
ldapBind();
});
});
res.on('end', function () {
callback(methodStatus);
});
});
}
and to invoke it in the way like this:
anmelden('user', 'pass', function (methodStatus){
console.log('the status is %s', methodStatus);
})
I am new to JavaScript.I am not understanding how to wait for a result of an Meteor.call method.
This is my code
//client/main.js
//Added the callback
Template.hello.events({
'click button'(event, instance) {
// increment the counter when button is clicked
instance.counter.set(instance.counter.get() + 1);
var res = Meteor.call("callMeLater","sanj",function (err,res) {
if (err) {
console.log(err);
} else {
console.log("this is the result main ", res);
}
});
console.log("this is the result ", res);
}
//server/main.js
Meteor.methods({
callMeLater :function (name) {
var callMeLaterSync =Meteor.wrapAsync(callMeLaterAsync);
var result = callMeLaterSync(name);
console.log("this is the test", result);
return result;
}
});
var callMeLaterAsync = function (name,cb) {
setTimeout(function () {
cb && cb (null ,"hey there, "+name);
},2000);
};
On the console, i get
this is the result undefined
this is the result main hey there, sanj
How do i wait for the result of Meteor.call by blocking the execution at the client.
Please help
Thanks
Just put your code into a callback method.
Meteor.call('callMeLater',"sanj", function(err, res){
if (err) {
console.log(err);
} else {
console.log("this is the result ", res);
}
});
I'm using mssql(Microsoft SQL Server client for Node.js) package from npm.I'm trying to execute a stored procedure residing in my sql server database.Everything works fine.However what I want to do is return the recordsets so that i can export this to be used in other module.Below is what I'm trying to do.
function monthlyIceCreamSalesReport (scope){
var connObj = connConfig();
connObj.conn.connect(function(err){
if(err){
console.log(err);
return;
}
connObj.req.input('Month',4);
connObj.req.input('Year',2016);
connObj.req.execute('<myStoredProcedure>', function(err, recordsets, returnValue){
if(err){
console.log(err);
}
else {
console.log(recordsets[0]); // successfully receiving the value
}
connObj.conn.close();
});
});
console.log('check for recordsets', recordsets[0]); // undefined
return recordsets[0];
}
var sqlServerObj = {
monICSalesReport : monthlyIceCreamSalesReport,
};
module.exports = sqlServerObj;
As shown in the code snippet, since the value of recordsets[0] is undefined, exporting this function is of no use.
You can't return this way in async nature. You can get it by passing the callback function
Try to give a callback function like this
function monthlyIceCreamSalesReport(scope, callback) { // pass a callback to get value
var connObj = connConfig();
connObj.conn.connect(function(err) {
if (err) {
console.log(err);
return;
}
connObj.req.input('Month', 4);
connObj.req.input('Year', 2016);
connObj.req.execute('<myStoredProcedure>', function(err, recordsets, returnValue) {
if (err) {
console.log(err);
} else {
console.log(recordsets[0]);
connObj.conn.close();
return callback(null, recordsets[0]); //return as a callback here and get that value in callback from where you called this function
}
});
});
}
var sqlServerObj = {
monICSalesReport: monthlyIceCreamSalesReport,
};
module.exports = sqlServerObj;
Note: See the comment to understand the changes
recordsets[0] is undefinded, because is defined only in connObj.req.execute function scope. You may do this in this way:
function monthlyIceCreamSalesReport (scope, cb){
var connObj = connConfig();
connObj.conn.connect(function(err){
if(err){
console.log(err);
return cb(Error("Something wrong"));
}
connObj.req.input('Month',4);
connObj.req.input('Year',2016);
connObj.req.execute('<myStoredProcedure>', function(err, recordsets, returnValue){
if(err){
console.log(err);
connObj.conn.close();
return cb(Error("Something wrong"));
}
else {
console.log(recordsets[0]); // successfully receiving the value
connObj.conn.close();
return cb(recordsets[0]);
}
});
});
}
var sqlServerObj = {
monICSalesReport : monthlyIceCreamSalesReport,
};
module.exports = sqlServerObj;
I would use the promises of angularJS to fill data to a grid. I'd like to load data "row by row" as soon as the nodeJS's server, on which use the module "mssql" with the "stream" enabled, back to client every single line from the DB.
On the client side I use these functions:
function asyncGreet() {
var deferred = $q.defer();
var _url = 'http://localhost:1212/test';
$http.get(_url).
then(function(result) {
deferred.resolve(result);
}, function(error) {
deferred.reject(error);
}, function(value) {
deferred.notify(value); //<<-- In "value" I would like to get every single row
});
return deferred.promise;
}
$scope.btnTest = function () {
var promise = asyncGreet();
promise.then(function(res) {
console.log('Success: ' + res.data + "\n");
}, function(reason) {
console.log('Failed: ' + reason);
}, function(update) {
console.log('Got notification: ' + update); //<<--
});
};
On nodeJS server those:
app.get('/test', function (req, res) {
//sql for test
var _query = 'select top 50 * from tb_test';
var sql = require('mssql');
var connection;
var config = {
user: 'testUser',
password: '12345',
server: 'localhost\\test',
database: 'testDB',
stream: true
};
connection = new sql.Connection(config, function (err) {
var request = new sql.Request(connection);
request.query(_query);
request.on('recordset', function(columns) {
// Emitted once for each recordset in a query
//res.send(columns);
});
request.on('row', function(row) {
res.write(JSON.stringify(row)); //<<-- I would like intercept this event on client side
// and get the result in my angularJS function on deferred.notify
});
request.on('error', function(err) {
// May be emitted multiple times
console.error(err)
});
request.on('done', function(returnValue) {
// Always emitted as the last one
res.end('DONE');
});
});
});
Anyone can help me with this?
Thanks!
I'm done it using socket.io :)
On angularJS side:
// count the row for test only
$scope.count = 0;
$scope.prova = function () {
mySocket.emit('getTableByRow', {});
mySocket.on('resRow', function (data) {
if (data.event == 'ROW') {
$scope.count += 1;
}else {
$scope.count += " !!DONE!! ";
}
});
};
On NodeJS side:
[ ... connection with DB ... ]
io.on('connection', function (socket) {
socket.on('getTableByRow', function (data) {
_getTableByRow(socket, data);
});
});
_getTableByRow function:
var _getTableByRow = function (socket, data) {
var _query = 'select top 50 * from tb_test';
request.query(_query);
request.on('row', function(row) {
// return only the ids for test
socket.emit('resRow', {event: 'ROW', data: row.id.toString()});
});
request.on('done', function(returnValue) {
socket.emit('resRow', {event: 'DONE'});
});
request.on('recordset', function(columns) {
console.log(columns);
});
request.on('error', function(err) {
socket.emit('resRow', {event: 'ERROR', data: err});
});
}
In this way, as soon as one row is read from the DB, it is immediately sent to the client :)
I'm using the mssql module to connect to a sql server database using node. Bluebird has a feature that's similar to resource management in c#. It has a 'using' method to avoid having to use try/catch/finall to dispose of the resources. They have examples for pg and mysql, but they don't have an example for mssql which doesn't create a connection the same way as pg and mysql. Here's an example of how to use it:
using(getConnection(),
fs.readFileAsync("file.sql", "utf8"), function(connection, fileContents) {
return connection.query(fileContents);
}).then(function() {
console.log("query successful and connection closed");
});
But to be able to use this method, you need to create a connection method which describes how to close the connection. Here's an example for pg:
function getSqlConnection(connectionString) {
var close;
return pg.connectAsync(connectionString).spread(function(client, done) {
close = done;
return client;
}).disposer(function(client) {
if (close) close(client);
});
}
The problem I'm having with mssql module is that the connect method doesn't return a connection object like pg or even the mysql module. Has anyone been able to do this with mssql?
Update 1:
Here's how I made the transaction disposer:
function getTransaction(connection) {
return new Promise(function(resolve, reject) {
var tx = sql.Transaction(connection);
tx.beginAsync().then(function(err) {
if(err) {
tx = null;
return reject(err);
}
return resolve(tx);
});
}).disposer(function(tx, promise) {
if(promise.isFulfilled()) {
return tx.commitAsync();
}
else {
return tx.rollbackAsync();
}
});
}
It seems to be working, but not sure if this is efficient. Now I need to figure out how to catch errors on a query.
This is how I'm doing a transaction:
using(getConnection(), function(connection) {
return using(getTransaction(connection), function(tx) {
return query(queryString, tx).then(function() {
console.log('first query in transaction completed.');
console.log('starting second query in transaction.');
return query(anotherQueryString, tx);
});
});
});
If I tag a single catch to the outer 'using', will that catch all errors from the whole transaction?
Good question, mssql has really tricky API (constructors taking callbacks!) so this is good addition to the documentation.
var Promise = require("bluebird");
var sql = Promise.promisifyAll(require("mssql"));
global.using = Promise.using;
function getConnection(config) {
var connection;
return new Promise(function(resolve, reject)
connection = new sql.Connection(config, function(err) {
if (err) {
connection = null;
return reject(err);
}
resolve(connection);
});
}).disposer(function() {
if (connection) connection.close();
});
}
var config = {
user: '...',
password: '...',
server: 'localhost',
database: '...',
};
using(getConnection(config), function(connection) {
var request = new sql.Request(connection);
return request.queryAsync("select 1 as number").then(function(recordSet) {
console.log("got record set", recordSet);
return request.queryAsync("select 10 as number");
});
}).then(function(recordSet) {
console.log("got record set", recordSet);
})
To use the transaction, try implementing getTransaction like:
function getTransaction(connection) {
var tx = new sql.Transaction(connection);
return tx.beginAsync().thenReturn(tx).disposer(function(tx, promise) {
return promise.isFulfilled() ? tx.commitAsync() : tx.rollbackAsync();
});
}
And using it like:
using(getConnection(), function(connection) {
return using(getTransaction(connection), function(tx) {
var request = new sql.Request(tx);
return request.queryAsync("INSERT 1...").then(function() {
return request.queryAsync("INSERT 2...");
}).then(function() {
return request.queryAsync("INSERT 3...");
});
});
});
Error handling:
using(getConnection(), function(connection) {
return using(getTransaction(connection), function(tx) {
var request = new sql.Request(tx);
return request.queryAsync("INSERT...");
});
}).catch(sql.TransactionError, function(e) {
console.log("transaction failed", e);
}).catch(sql.ConnectionError, function(e) {
console.log("connection failed", e);
}).catch(sql.RequestError, function(e) {
console.log("invalid query", e);
});