Async parallel and promises wont work - node.js

I have the following two snippets:
1.this is the unit I would like to run:
health.checkHealth = function (req, res) {
async.parallel({
cassandra: function (callback) {
cassandraRepository.ping(callback);
},
kafka: function (callback) {
kafkaHelper.ping(callback);
},
vault: function (callback) {
vaultClient.health()
.then((isOk)=>{
callback(null, isOk)})
.catch(()=>
callback(null, false));
}
}, function (err, result) {
var response = {};
if (result.cassandra) {
response.cassandra = "OK";
} else {
response.cassandra = "Failed";
res.status(500);
}
if (result.kafka) {
response.kafka = "OK";
} else {
response.kafka = "Failed";
res.status(500);
}
if (result.vault) {
response.vault = "OK";
} else {
response.vault = "Failed";
res.status(500);
}
res.send(response);
})
}
2.this is the test to check the unit:
describe('vault is avaliable', function () {
beforeEach(sinon.test(function () {
sinon.stub(vaultClient, "health").resolves(true);
}));
it('should return 200', sinon.test(function (done) {
var response = {
vault: "OK"
};
var req = {};
var res = {};
var spySend = res.send = sinon.spy();
var spyStatus = res.status = sinon.spy();
health.checkHealth(req, res);
expect(spySend.calledOnce).to.equal(true);
expect(spySend.calledWith(response));
expect(spyStatus.calledOnce).to.equal(false);
}));
});
My problem is that when I call checkHealth it proceeds to the next line (expect(spySend.calledOnce).to.equal(true);) without waiting for the vaultClient's promise to complete.
What do I need to do to make the expects run only after the 'checkHealth' was run.

You do not need to use the async - you can use promises directly in your code with Promise.all as others have suggested.
The code here is using promisifyAll from Bluebird, but you can also convert the APIs to use promises yourself.
//.props is bluebird, you can `.all` with native promises too
Promise.props({
cassandra: cassandraRepository.pingAsync(); // created by promisifyAll
kafka: kafkaHelper.pingAsync(),
vault: vaultClient.health()
}).then(results => {
// access results.cassandra, results.kafka and results.vaule here
});

Related

nodejs: Not able to read response from callback function in the main function

Noob in nodejs here and still trying to learn how nodejs works. Could you please let me know how can I pass the callback response from "getDatafromCosmosDB" function into a variable in the main function and print those values.
When I try to assign getDatafromCosmosDB to a variable "respdata" and try to print it, it is not working.
async function main(params, callback) {
const logger = Core.Logger('main2', { level: params.LOG_LEVEL || 'info' })
try {
logger.info('main action')
const respdata = getDatafromCosmosDB(function(response){
console.debug(response)
return response
});
console.debug(respdata)
} catch (e) {
console.debug(e)
}
}
exports.main = main
async function getDatafromCosmosDB(callback){
var query = new azure.TableQuery()
.top(5)
tableService.queryEntities('myCosmosTable', query, null, function (error, result, response) {
if (!error) {
console.log('success')
return callback(result.entries)
}
});
}
Try something like this,
import {
createTableService,
services,
ServiceResponse,
TableQuery
} from 'azure-storage';
getDatafromCosmosDB(): Promise<ServiceResponse> {
return new Promise(async (resolve, reject) => {
this.tableService.queryEntities(
this.tableName,
query,
null,
(error, _, response) => {
if (!error) {
resolve(response);
} else {
reject(error);
}
}
);
});
}
and invoke like,
this.getDatafromCosmosDB().then(data => {
console.log(data);
}

Async series is not calling properly

I have 3 function has to call in series one after the other. but first function is exeucting and in between second and third are executing.
var tasklist=[api_hit,delay,mysql_check];
if(task_list.length>0){
async.series(
tasklist,
function(err, response) {
console.log(err);
console.log(response);
results.data=response;
results.message="Completed";
console.log(results);
}
);
}
Internal functions:
function api_hit(callback){
console.log("Inside api");
var ele=task_list[0];
var apidata=[];
var msg={'data':[]};
apiinfo.forEach((item,key)=>{
if(item.Method_name==ele.Parameters){
//Here checking random Int value
if(item.Value=="{{$randomInt}}"){
item.Value = generate(25);
}
apidata.push(item);
}
});
var data=[];
data['api']=apidata;
apiModel.validateAPI(data,function(res){
console.log("result api");
msg.data=res;
msg.case='api_hit';
callback(msg);
});
}
function delay(callback){
console.log("Inside delay");
var msg={'data':[]};
global_vars.sleep(1000);
msg.data='success';
msg.case='task';
console.log("after delay");
callback(msg);
}
function mysql_check(callback){
console.log("inside mysql");
var ele=task_list[2];
var dbdata=[];
var msg={'data':[]};
dbchecks.forEach((item,key)=>{
if(item.query_id==ele.Parameters){
console.log(item.query+" ::: "+ele.Parameters);
dbdata.push(item);
}
});
data['dbdata']=dbdata;
apiModel.checkmysql(data,function(err,res){
if(err) throw err;
console.log("inside mysql res");
msg.data=res;
msg.case='task2';
callback(msg);
});
}
My intention is to call these function after completing of others and all the results has to process in a single variable. but in api_hit method when it is executing another function inside of it then delay()(second function of async) is executing. how to stop this and make it in sequence. thanks in advance.
The first argument to the callback function is the error, pass null in case of success.
'use strict'
const async = require('async')
function api_hit(callback) {
setTimeout(() => {
console.log('Completed api_hit')
callback(null, 'api_hit')
}, 1000)
}
function delay(callback) {
setTimeout(() => {
console.log('Completed delay')
callback(null, 'delay')
}, 100)
}
function mysql_check(callback) {
setTimeout(() => {
console.log('Completed mysql_check')
callback(null, 'mysql_check')
}, 500)
}
var tasklist = [api_hit, delay, mysql_check];
if (tasklist.length > 0) {
async.series(
tasklist,
function (err, response) {
console.log(err);
console.log(response);
}
);
}
Doc link: https://caolan.github.io/async/docs.html#series

Function enters then before request completed

My async function enters then before request is completed. Shouldn't Then part of the code executes only after the async function is completed? How to make the function call only when all the function has finished executing?
app.js
var request_test = require('./request_test');
baseUrl = "https://github.com";
promiseFunction().then((result)=>{
console.log("complete")
});
var promiseFunction = async function promiseFunction() {
request_test.request_test(baseUrl);
}
request_test.js
var request = require('request');
var cheerio = require('cheerio');
var request_test = function check(baseUrl) {
console.log("baseUrl:" + baseUrl)
var options = {
url: baseUrl
};
request(options, function (error, response, html) {
if (!error) {
console.log("no error");
}else{
console.log("else js");
console.log(error);
}
});
}
module.exports = {
request_test: request_test
};
In order to use then() you need to return a promise. So here is an example of the good old style promise chain, simply return promise from request_test and once you resolve or reject it, then() will be called:
promiseFunction().then((result) => {
console.log("complete");
});
function promiseFunction() {
return request_test();
}
function request_test() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log("no error");
resolve();
}, 1000);
});
}
Or maybe use the modern approach - async method to await call function that returns promise.
promiseFunction();
async function promiseFunction() {
await request_test();
console.log('complete');
}
function request_test() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log("no error");
resolve();
}, 1000);
});
}
Your issue is coming from var request_test = function check(baseUrl) { ... inside this function you are not returning promise, you are even returning nothing :)
if you are using async I would go ahead and use the await/async syntax. Also the package request does not return a promise, you have an alternative with request-promise-native. The promise should be the return value of your helper function. It could look like this:
var request_test = require('./request_test');
var baseUrl = "https://github.com";
var promiseFunction = async function () {
var result = await request_test.request_test(baseUrl);
console.log("complete");
}
promiseFunction();
and the module:
var request = require('request-promise-native');
var cheerio = require('cheerio');
var request_test = function check(baseUrl) {
console.log("baseUrl:" + baseUrl)
var options = {
url: baseUrl
};
return request(options).then(function (error, response, html) {
if (!error) {
console.log("no error");
} else{
console.log("else js");
console.log(error);
}
});
}
module.exports = {
request_test: request_test
};

Bluebird - promisification - promisifyAll of 'email-templates' Node Module - Send mail

I am trying to convert email-templates node module into promise. I am using bluebird for promisification but it couldn't converted.
var emailTemplates = Promise.promisifyAll(require('email-templates'));
Is promisification node module supports this conversion or Am I doing any mistake?
EDITED :
I am doing like this now but wanna convert this to bluebird promise.
var emailTemplates = require('email-templates');
var path = require('path');
var templatesDir = path.resolve(__dirname, '../..', 'assets/templates');
var postmark = require('postmark');
var postmarkKey = MY_POSTMARK_KEY;
var postmarkClient = postmark(postmarkKey);
module.exports = {
sendEmail : function (templateName, locals, callback) {
emailTemplates(templatesDir, function (err, template) {
if (err)
return callback(err, null);
else {
template(templateName, locals, function (err, html, text) {
if (err) {
return callback(err, null);
}
else {
postmarkClient.send({
From: locals.from,
To: locals.to,
Subject: locals.subject,
HtmlBody: html
TextBody: text
}, function (err, responseStatus) {
if (err) {
return callback(err, null);
}
else {
return callback(err, responseStatus);
}
});
}
});
}
});
}
}
emailTemplates is a function, so you'd do:
var emailTemplates = Promise.promisify(require('email-templates'));
The problem is that it does not behave well since the function itself has a callback argument, so you'd have to do:
emailTemplates().then(function(template){
Promise.fromNode(template.bind(null, "template-name")).then(...
});
Promisify missbehaved for me as well, so i made a manual promisification.
var postmark = require("postmark");
var client = new postmark.Client("POSTMARK_API_TEST");
var Promise = require('bluebird');
exports.sendInviteEmail = function(email) {
let promise = new Promise((resolve, reject) => {
client.sendEmail({
"From": "donotreply#example.com",
"To": "target#example.us",
"Subject": "Test",
"TextBody": "Test Message"
}, function(error, result) {
if(error) {
reject(error);
} else {
resolve(result);
}
})
});
return promise;
}

node.js stubbing AWS S3 method in request spec with sinon

I've got an express based app running on node.js 0.12.2 which uses the s3.headBucket method from aws-sdk 2.1.22 to return a JSON response depending upon whether a particular bucket exists or not.
I've been struggling to directly stub out the call to s3.headBucket with sinon. I've managed to work around this by creating an s3wrapper module which just requires the aws-sdk and instantiates and returns the s3 variable, however, I'm sure this can be done without using the wrapper module and can instead be stubbed directly with sinon, can anyone point me in the right direction?
Below is the currently working code (with the wrapper module s3wrapper.js which I'd like to remove and handle the stubbing in my status_router_spec.js file). In other words, I'd like to be able to call s3.headBucket({Bucket: 'whatever' ... instead of s3wrapper.headBucket({Bucket: ' ... and be able to stub out this s3.headBucket call with my own response.
status_router_spec.js
var chai = require('chai'),
sinon = require('sinon'),
request = require('request'),
myHelper = require('../request_helper')
var expect = chai.expect
var s3wrapper = require('../../helpers/s3wrapper')
describe('My router', function () {
describe('checking the service status', function () {
var headBucketStub
beforeEach(function () {
headBucketStub = sinon.stub(s3wrapper, 'headBucket')
})
afterEach(function () {
s3wrapper.headBucket.restore()
})
describe('when no errors are returned', function () {
it('returns healthy response', function (done) {
// pass null to represent no errors
headBucketStub.yields(null)
request.get(myHelper.appUrl('/status'), function (err, resp, body) {
if (err) { done(err) }
expect(JSON.parse(body)).to.deep.eql({
healthy: true,
message: 'success'
})
done()
})
})
})
})
})
s3wrapper.js
var AWS = require('aws-sdk')
var s3 = new AWS.S3()
module.exports = s3
status_router.js
var Router = require('express').Router
var s3wrapper = require('../helpers/s3wrapper.js')
var router = new Router()
function statusHandler (req, res) {
s3wrapper.headBucket({Bucket: 'some-bucket-id'}, function (err) {
if (err) {
return res.json({ healthy: false, message: err })
} else {
return res.json({ healthy: true, message: 'success' })
}
})
}
router.get(/^\/status\/?$/, statusHandler)
module.exports = router
Answering this question for the benefit of #ippomakunochi who requested a follow up response.
We ended up using rewire to directly set a stub on the s3 library. For example, we stubbed the getObject call for the s3 library using the following:
s3stub = { getObject: sinon.stub(), listObjects: sinon.stub() }
revert = s3.__set__('s3', s3stub)
Here's the complete code:
../../../build/app/helpers/s3
var AWS = require('aws-sdk');
var s3 = new AWS.S3();
module.exports = {
get: function get(options, callback) {
var requestOptions = { Bucket: module.exports.bucket(), Key: options.productId + '.json' };
s3.getObject(requestOptions, function (err, data) {
if (err) { // handle err }
try {
var productData = JSON.parse(data.Body);
} catch (e) {
// handle error
}
return callback(null, productData);
});
}
}
}
test/unit/app/helpers/s3_spec.js
var AWS = require('aws-sdk')
var chai = require('chai')
var sinon = require('sinon')
var sinonChai = require('sinon-chai')
var chaiSubset = require('chai-subset')
var rewire = require('rewire')
var s3 = rewire('../../../build/app/helpers/s3')
chai.use(chaiSubset)
chai.use(sinonChai)
var expect = chai.expect
describe('S3', function () {
var s3stub, revert
beforeEach(function () {
s3stub = { getObject: sinon.stub(), listObjects: sinon.stub() }
revert = s3.__set__('s3', s3stub)
})
afterEach(function () {
revert()
})
describe('#get', function () {
context('when no errors are returned by s3', function () {
it('returns a product', function (done) {
var productResponse = helper.fixture.body('product.json')
s3stub.getObject.yields(null, productResponse)
s3.get({ productId: '1234' }, function (err, res) {
expect(err).to.not.exist
expect(res).to.containSubset({name: 'long sleeve shirt', 'retailer_code': 'retailer-1'})
done()
})
})
})
context('when s3 returns a NoSuchKey error', function () {
it('returns a NotFoundError', function (done) {
var s3Error = AWS.util.error(new Error(), { name: 'NoSuchKey' })
s3stub.getObject.yields(s3Error)
s3.get({ productId: '1234' }, function (err) {
expect(err.message).to.eql('1234 is not found in s3')
expect(err.output.statusCode).to.eql(404)
done()
})
})
})
})

Resources