In the following code, why does the createFile callback fire twice? This only happens when the server (below) is processing two or more requests at the same time, not if only one request has been made. Output at the bottom of the post. The client making the request is not a browser, but another node.js script iterating through a directory and sending a http post request with the file to the server. The request is created like this:
fs.createReadStream(fileName).pipe(httprequest(options, function(error, response, body) { }));
function myRequest(request, response) {
function writeFile(filePath, request, callback) {
newFilePath = "/home/pi/upload"+filePath; //filePath looks like this: /home/blah/file.txt, the code below creates this structure under another directory, so newFilePath becomes /home/pi/upload/home/blah/file.txt
tempFileName = path.basename(filePath)+".temp";
console.log("Processing "+filePath+"->"+newFilePath+" with tempname " +tempFileName);
var createFile = request.pipe(fs.createWriteStream(tempFileName));
createFile.on("finish", function(error) { //Why does it fire the callback twice?
if(error) {
throw error;
} else {
moveFile(tempFileName, newFilePath, function(error) {
if(error) {
throw error;
} else {
console.log("OK");
}
});
}
});
}
function moveFile(tempFileName, newFilePath, callback) {
dirPath = path.dirname(newFilePath);
fs.stat(dirPath, function(error, stats) { //check if dir exists
if(error == null) {
console.log(dirPath+" already exists");
fs.stat(tempFileName, function(error, stats) { //check if file exists
if(error == null) {
console.log("OK, writing "+newFilePath);
fs.rename(tempFileName, newFilePath, function(error) {
if(error) { //Error on the second run, because the file has been moved in the first run, shouldn't happen?
throw error;
} else {
var myCB = JSON.stringify({fMove: "OK"});
callback(myCB);
}
});
} else {
console.log("File exists");
}
});
}
});
}
writeFile(fileName, request, function() {
//Do some stuff
});
request.on("end", function() {
//Do other stuff
}
});
http.createServer(myRequest).listen(8888);
Output from my script
Processing /home/pi/app/temp/client.js->/home/pi/upload/home/pi/app/temp/client.js with tempname client.js.temp
/home/pi/upload/home/pi/app/temp already exists
/home/pi/upload/home/pi/app/temp already exists
OK, Writing /home/pi/upload/home/pi/app/temp/client.js
OK, Writing /home/pi/upload/home/pi/app/temp/client.js
/home/pi/app/server.js:67
throw error;
^
{"fMove":"OK"}
Incorrect error handling made the script faulty.
In the moveFile function this part was wrong:
fs.rename(tempFileName, newFilePath, function(error) {
if(error) {
throw error;
} else {
var myCB = JSON.stringify({fMove: "OK"});
callback(myCB); // <-- Malformatted callback! Should be callback(null, myCB);
}
Which made this part of writeFile trigger on error and for some reason run twice:
moveFile(tempFileName, newFilePath, function(error) { //Should be moveFile(tempFileName, newFilePath, function(error, status) {
if(error) {
throw error;
} else {
console.log("OK");
}
});
When I fixed my code so it handles the error correctly, it works as intended!
Related
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;
Node.js:
var https = require("https");
var request = https.get("google.com/", function(response) {
console.log(response.statusCode);
});
request.on("error", function(error) {
console.log(error.message);
});
If I add https:// to the google domain name then I get the status code 200 as expected. As is, I would expect the error to be caught and an error message similar to "connect ECONNREFUSED" to be printed to the terminal console. Instead it prints the stacktrace to the terminal.
If you look at the source for https.get(), you can see that if the parsing of the URL fails (which it will when you only pass it "google.com/" since that isn't a valid URL), then it throws synchronously:
exports.get = function(options, cb) {
var req = exports.request(options, cb);
req.end();
return req;
};
exports.request = function(options, cb) {
if (typeof options === 'string') {
options = url.parse(options);
if (!options.hostname) {
throw new Error('Unable to determine the domain name');
}
} else {
options = util._extend({}, options);
}
options._defaultAgent = globalAgent;
return http.request(options, cb);
};
So, if you want to catch that particular type of error, you need a try/catch around your call to https.get() like this:
var https = require("https");
try {
var request = https.get("google.com/", function(response) {
console.log(response.statusCode);
}).on("error", function(error) {
console.log(error.message);
});
} catch(e) {
console.log(e);
}
I am trying to run queries again my database using node-mssql. Everything works perfect. But when I try to execute queries within a transaction, transaction gets committed but tables remain empty. Can someone check whats wrong with the code:
var transaction = new sql.Transaction(/* [connection] */);
transaction.begin(function(err) {
// ... error checks
console.log("[Info]","Begin Transaction.");
if(err) {
console.log(err);
process.exit(-1)
}
var request = new sql.Request(transaction);
var transactionFailed = false;
var request = new sql.Request(transaction);
//request.multiple = true;
request.verbose = true;
request.query(upsertQuery);
console.log("[Info]",request)
request.on('error', function(err) {
transactionFailed = true;
console.log(['Error'],err.toString())
});
request.on('done', function(errs) {
if(transactionFailed) {
transaction.rollback(function(err) {
if(err) {
console.log(err);
process.exit(-1)
}
else {
process.exit(-1)
}
});
}
else {
transaction.commit(function(err) {
if(err) {
console.log(err);
process.exit(-1)
}
else {
console.log("Transaction Committed!")
}
});
}
});
});
Issue was with my sql query. the above code works fine
I am Learning Meteor and Javascript. I am using an npm package to get meta data of an url on the server side. This works fine. But I get undefined when passing that result back to client. Would appreciate some help.
Here is my code
if (Meteor.isClient) {
Meteor.call('getMetaData', "http://www.bbc.co.uk/news", function (err, data) {
if (err) {
console.log("error", err);
};
console.log("Meta data: " + data); //shows undefined
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
var preview = Meteor.npmRequire('page-previewer');
Meteor.methods({
getMetaData: function (url) {
preview(url, function (err, data) {
if (!err) {
console.log(data); //Works fine
return data;
}
});
}
})
});
}
You need to convert the preview function to an synchronous function,using Future like this, this will make this function wait normal err,data callbacks into a synchronous function.
var Future = Npm.require('fibers/future'),
preview = Meteor.npmRequire('page-previewer');
Meteor.methods({
getMetaData: function(url) {
var f = new Future();
preview(url, function(err, data) {
if (!err) {
return f.return(data);
}
});
return f.wait();
}
});
Now this snippet should work
if (Meteor.isClient) {
Meteor.call('getMetaData', "http://www.bbc.co.uk/news", function (err, data) {
if (err) {
console.log("error", err);
}else{
console.log("Meta data: " + data); //shows undefined
}
});
};
try using else block to get the meta data. here's a solution of a similar problem .
https://forums.meteor.com/t/client-getting-undefined-for-server-method/6129/4?u=faysal
so basically you need to add only one extra line
else{ console.log('metadata '+ data);}
I have a simple route defined with express.js:
exports.save = function (request, response)
{
var file = request.body.file;
var content = request.body.content;
var saved = false;
if (fs.existsSync( file ))
{
saved = fs.writeFileSync(file, content, 'utf8');
}
console.log( saved ); // undefined or false, never true
response.send(saved ? 200 : 500, saved ? 'saved' : 'error'); // 500, error
};
Is if (typeof saved === 'undefined') saved = true; the only option? Feels hacky.
According to node.js source-code fs.writeFileSync doesn't return anything.
It throws an Error object if something goes wrong. So you should write fs.writeFileSync(file, content, 'utf8'); within a try-catch block.
fs.writeFileSync does not return any value, if there is no exception happens that means the save succeeded; otherwise failed.
you may want to try the async version of file read
fs.exists(file, function (exists) {
if (exists) {
fs.writeFiles(file, content, 'utf-8', function (err) {
if (err) {
response.send("failed to save");
} else {
response.send("succeeded in saving");
}
} else {
console.log('file does not exists');
}
}
fs.exists(file, function (exists) {
if (exists) {
fs.writeFiles(file, content, err=> {
if (err) res.status(500).send({error: "failed to save"});
else res.status(200).send({message : "succeeded in saving"});
} else {
res.status(404).send({error: "file not exists"})
}
}
Use async instead of sync. This will work.