I need to run queries jobs at specific dates, After researching nodejs libraries for that node schedule was more recommended then node-cron because it handles better for one time jobs then for repetitive jobs.
The problem is that sometimes the job is running like it should and sometimes it not running i'm not getting any error.
Usually the cron jobs does not get executed if the selected date is longer then 2 hours and works properly if the selected date is 30 minutes or less.
I tried both node-cron and node schedule libraries, i added error handler to catch the error when cron job does not get executed but no error is thrown when the job is not getting executed.
route.js :
router.put('/preview', auth, async (req, res) => {
const auctionId = req.body.auctionId;
const auctionStartDate = req.body.auctionStartDate;
let bidEndDate = req.body.bidEndDate;
let auctionEndDate = req.body.auctionEndDate;
const chargeableWeight = req.body.chargeableWeight;
//create auction serial number if the auctions is new and not modified
await db.query(
`SELECT right(AuctionSerialNumber,length(AuctionSerialNumber)-1) as serialCount
FROM auctions
ORDER BY cast(right(AuctionSerialNumber,length(AuctionSerialNumber)-1) as unsigned) DESC
LIMIT 1`,
async (error2, results2, fields2) => {
if (error2) res.status(400).json({ errors: error2.message });
let serialCount = results2[0].serialCount;
let tempSerialNumber = parseInt(serialCount, 10);
let nextSerial = tempSerialNumber + 1;
nextSerial = 'A' + nextSerial;
await db.query(
`UPDATE fretit.auctions SET
fretit.auctions.AuctionEndDate = '${auctionEndDate}',
fretit.auctions.StartDate='${auctionStartDate}',
fretit.auctions.BidEndDate='${bidEndDate}',
fretit.auctions.AuctionSerialNumber='${nextSerial}',
fretit.auctions.AuctionState=2,
fretit.auctions.WinningBidID='000',
fretit.auctions.ChargeableWeight='${chargeableWeight}'
WHERE fretit.auctions.UID='${auctionId}'`,
(error, result, fields) => {
if (error) res.status(400).json({ errors: error.message });
}
);
//start bid end date timer
var j1 = schedule.scheduleJob(bidEndDate, async () => {
console.log('starting bid end date');
await db.query(
`SELECT auctions.AuctionState as auctionState
FROM auctions
WHERE auctions.UID='${auctionId}'
`,
async (error2, result2, fields2) => {
if (error2) res.status(400).json({ errors: error.message });
let auctionState = result2[0].auctionState;
console.log(auctionState);
//if auction state is LiveNoBids give notification and start auction end date
if (auctionState == 2) {
await db.query(
`UPDATE auctions SET
auctions.AuctionLostNotification=1,
auctions.AuctionState=4
WHERE auctions.UID='${auctionId}'
`,
(error, result, fields) => {
if (error) res.status(400).json({ errors: error.message });
var j3 = schedule.scheduleJob(auctionEndDate, async () => {
console.log(auctionEndDate);
console.log(
'this auction reached bidEndDate and does not have bids'
);
await db.query(
`SELECT auctions.AuctionState as auctionState
FROM auctions
WHERE auctions.UID='${auctionId}'
`,
async (error2, results2, fields2) => {
if (error2)
res.status(400).json({ errors: error.message });
let auctionState = results2[0].auctionState;
console.log(auctionState);
//if auction state is DueDateExceeded when auctionEndDate ends move auction state to Expired
if (auctionState == 4) {
console.log(auctionState);
await db.query(
`UPDATE auctions SET
auctions.AuctionState=7
WHERE auctions.UID='${auctionId}'
`,
(error3, result3, fields3) => {
if (error3)
res
.status(400)
.json({ errors: error.message });
}
);
}
}
);
});
}
);
//if auction state is LiveWithBids move auction state to DueDateExceeded
} else if (auctionState == 3) {
console.log(auctionState);
await db.query(
`UPDATE auctions SET
auctions.AuctionState=4,
auctions.AuctionWonNotification=1
WHERE auctions.UID='${auctionId}'
`,
(error, result, fields) => {
if (error) res.status(400).json({ errors: error.message });
//start auction end date timer
var j2 = schedule.scheduleJob(auctionEndDate, async () => {
console.log(auctionEndDate);
console.log(
'this auction reached bidEndDate and have bids'
);
await db.query(
`SELECT auctions.AuctionState as auctionState
FROM auctions
WHERE auctions.UID='${auctionId}'
`,
async (error2, result2, fields2) => {
if (error2)
res.status(400).json({ errors: error.message });
let auctionState = result2[0].auctionState;
console.log(auctionState);
//if auction state is DueDateExceeded when auctionEndDate ends move auction state to Expired
if (auctionState == 4) {
console.log(auctionState);
await db.query(
`UPDATE auctions SET
auctions.AuctionState=7
WHERE auctions.UID='${auctionId}'
`,
(error3, result3, fields3) => {
if (error3)
res
.status(400)
.json({ errors: error.message });
}
);
}
}
);
});
}
);
}
}
);
});
}
);
});
catchErrorAsync.js:
module.exports = function(handler) {
return async (req, res, next) => {
try {
await handler(req, res);
} catch (ex) {
next(ex);
}
};
};
error.js:
const winston = require('winston');
module.exports = function(err, req, res, next) {
// log error message to file
winston.error(err.message, err);
// Send a user-friendly message back to the user
res.status(500).send('Something went wrong...');
};
Why the cron jobs sometimes working and sometimes not?
What is the correct library to use for this usage?
Related
I am recieving this error: Cannot set headers after they are sent to the client
I take that to mean the code is attempting to set the response headers more than once. This is the code, but I cant seem to find out where the headers are being set twice.
async function createTrip(request, response) {
const { vehicleId, driverId, startedAt, expectedReturn } = request.body
let driver, vehicle
//validation
await pool.query(
'SELECT * FROM Vehicle WHERE id = $1',
[vehicleId],
(error, results) => {
if (error) {
throw `ERROR::createTrip threw an error: ${error}`
}
if (results.rowCount === 0) {
return response.send({ status: 404, message: `vehicle with id ${vehicleId} does not exist.` })
} else if (results.rows[0].in_use) {
return response.send(403).send({ status: 403, message: `vehicle with id ${vehicleId} is not available for rental` })
} else {
vehicle = results.rows[0]
}
}
)
await pool.query(
'SELECT * FROM Driver WHERE id = $1',
[driverId],
(error, results) => {
if (error) {
throw new Error(`ERROR::createTrip threw an error: ${error}`)
} else if (results.rowCount === 0) {
return response.status(404).send({ status: 404, message: `driver with id ${driverId} does not exist` })
} else {
driver = results.rows[0]
}
}
)
//event
await pool.query(
'INSERT INTO Trip (status,started_at, expected_return, driver, vehicle) VALUES ($1,$2,$3,$4,$5) RETURNING *',
['active', startedAt, expectedReturn, driverId, vehicleId],
(error, results) => {
if (error) {
throw `ERROR::createTrip threw an error: ${error}`
} else {
return response.status(200).send({ id: results.rows[0].id, status: results.rows[0].status, startedAt, expectedReturn, driver, vehicle })
}
}
)
await pool.query(
'UPDATE Vehicle SET in_use = TRUE WHERE id = $1',
[vehicleId],
(error) =>{
if(error){
throw `ERROR::createTrip threw an error: ${error}`
}
}
)
}
Your createTrip function does four queries. Each of those queries results in a response potentially being called. You should do all the processing from all the queries you need to inside a try/catch block. Then, instead of sending a response when rowCount === 0 for example, throw an error, catch it in the catch block and send the response from there.
If my controller makes multiple db queries in the same async function should each db query be wrapped in it's own individual try/catch block or is it fine to have all db queries in the same try/catch? What is the reasoning for either option?
All db queries in their own try/catch example:
const confirmEmailVerification = async (req, res) => {
const { token } = req.body;
let user;
try {
const result = await db.query(
'SELECT user_account_id FROM user_account WHERE email_verification_token = $1',
[token]
);
if (result.rows.length === 0) {
return res
.status(400)
.json('Please verify your account by clicking the link in your email');
}
user = result.rows[0].user_account_id;
} catch (err) {
console.error(err.message);
return res.status(500).json('Server Error');
}
try {
const active = await db.query(
'UPDATE user_account SET email_verified = TRUE WHERE user_account_id = $1',
[user]
);
return res.status(200).json({
message: 'Email has been verified, Please login',
});
} catch (err) {
console.error(err.message);
return res.status(500).json('Server Error');
}
};
All db queries in the same try/catch example:
const confirmEmailVerification = async (req, res) => {
const { token } = req.body;
let user;
try {
const result = await db.query(
'SELECT user_account_id FROM user_account WHERE email_verification_token = $1',
[token]
);
if (result.rows.length === 0) {
return res
.status(400)
.json('Please verify your account by clicking the link in your email');
}
user = result.rows[0].user_account_id;
const active = await db.query(
'UPDATE user_account SET email_verified = TRUE WHERE user_account_id = $1',
[user]
);
return res.status(200).json({
message: 'Email has been verified, Please login',
});
} catch (err) {
console.error(err.message);
return res.status(500).json('Server Error');
}
};
This depends on that, if you want the sequence of functions to continue after previous function throws error.
In your case it is useless, because in either errors you finish with res.status(500).json('Server Error').
But sometimes you want to continue, even if some of the functions in the chain throws error, eg.:
let errors = []
try {
f1()
} catch (e) {
errors.push(e)
}
try {
f2()
} catch (e) {
errors.push(e)
}
try {
f3()
} catch (e) {
errors.push(e)
}
If you put this is in one try/catch block, you would stop on the error of f1() and f2() and f3() would not be ran at all.
try {
f1()
f2()
f3()
} catch (e) {
something...
}
I'm trying to develop an API post, in middle execution I have validation such as check name already in use or not. I set error handler callback, it successfully send response 'Already registered', but when I checked to CLI, it show error
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
I dont know whats wrong, I use this error handler in the past and it seems look ok.
Here is my code in router:
createUserAccount: async function (req, res) {
const programData = req.body;
try {
await service.create(programData, function (code, err, result) {
if (err) {
if(code === 409){
res.status(HTTPSTATUS.CONFLICT).send(err.message);
} else {
res.status(HTTPSTATUS.BAD_REQUEST).send(err.message);
}
} else {
res.status(HTTPSTATUS.CREATED).json(result);
}
})
} catch (e) {
console.log(e)
res.status(HTTPSTATUS.BAD_REQUEST).json("Failed.");
}
Here is my function in my service:
const config = require('#configs/config.json')
const sequelize = require('sequelize');
const SEQUELIZE = new sequelize(config[env]);
module.exports = {
createAccount: async (name, password, callback) => {
try {
let check,
institution_id;
const checkName = await Profile.count(
{
where: {
name: name
}
}
);
//result checkName = 1
if(checkName > 0){
//then successfully execute this condition and
return callback(409, 'Already registered.', null);
//this show in console ----> POST /API/v1/user/profile 409 616.152 ms - 31
}
await Login.create({
username: email,
password: password
}).then(resLogin => {
const response = {
id: resLogin.id,
}
callback(201, null, response);
}).catch( error => {
callback(400, error, null);
})
} catch (e) {
callback(400, e, null);
}
},
create: async (payload, callback) => {
let loginID = null;
let {
profile,
address
} = payload;
let {
name,
email,
password
} = profile;
try {
await module.exports.createAccount(name, password, function (code, error, result) {
if(error){
const res = {message: error};
//what I need is the execution is end in here
return callback(code, res, null);
}
loginID = result.id;
});
//but the fact is it still execute this whole function if got callback error from createAccount()
let transaction = await SEQUELIZE.transaction();
await Address.create(address, {transaction})
.then( async resAddress => {
await transaction.commit();
return callback(201, null, resProfile);
}).catch(async e => {
return callback(400, e, null);
})
} catch (e) {
console.log(e);
callback(e, null);
}
};
I try the response model after create data but it doesn't work. It shows data on "console.log" and it didn't respond when I use "resolve({})".
In the routers.js:
const register = require('./functions/register');
module.exports = router => {
router.get('/', (req, res) => res.end('Welcome to Idol Fan With your Idol !'));
//======REGISTER & LOGIN WITH SOCIAL =====
router.post('/socialuser', (req, res) => {
const social_id = req.body.social_id;
const token = req.body.token;
const name = req.body.name;
const email = req.body.email;
const photoprofile = req.body.photoprofile;
const tokenfirebase = req.body.tokenfirebase;
if (!social_id) {
res.status(400).json({message: 'Invalid Request !'});
} else {
register.registerUser(social_id, name, email, photoprofile, token, tokenfirebase)
.then(result => {
res.status(result.status).json({status: result.status, message: result.message, user: result.user})
})
.catch(err => res.status(err.status).json({message: err.message}));
}
});
}
Function Register.js:
const userfan = require('../models/user');
exports.registerUser = (social_id, name, email, photoprofile, token,
tokenfirebase) =>
new Promise((resolve, reject) => {
const d = new Date();
const timeStamp = d.getTime();
userfan.find({social_id: social_id})
.then(users => {
if (users.length == 0) {
let newUser = new userfan({
social_id: social_id,
name: name,
email: email,
photoprofile: photoprofile,
token: token,
tokenfirebase: tokenfirebase,
created_at: timeStamp
});
newUser.save()
.then(doc => {
console.log("run... " + doc);
resolve({
status: 200,
message: 'User Register Sucessfully !',
user: doc
});
})
.catch(err => {
console.error(err)
if (err.code == 11000) {
reject({status: 409, message: 'User Already Registered !'});
} else {
reject({status: 500, message: 'Internal Server Error !'});
}
});
} else {
return users[0];
}
})
.then(usertemp => resolve({status: 200, message: "Login Successfully !", user: usertemp}))
.catch(err => {
console.log(err.message);
reject({status: 500, message: err.message});
});
});
This is my result after run on server:
As a result and code above. I have a question Why "user: doc" no response?. Thank you so much!
userfan.find.then.then (synchronous since nothing requires waiting) is called before newUser.save.then (asynchronous since under the hood it waits for the DB to answer).
So both resolve are called, but only the first call is considered, and the first one to be called is the one using usertemp. And this one receives undefined as argument, because of the implicit return undefined at the end of userfan.find.then.
Your flow should be:
userfan.find().then(users => {
if (!users.length) {
let newUser = ...
// explicitly return the promise, which will give the created user
return newUser.save().then(doc => {
// format and return the value you want
return {user: doc, message: 'registered'};
});
} else {
// another explicitly returned value, but you already have this
return {user: users[0], message: 'login'};
}
// it's not possible here because we returned before it, but your code reached this point
// and, implicitly, any function ending with no return does:
return undefined;
// this .then receives *either* the promise from newUser.save *or* the object from the else block
}).then(structure => {
structure.status = 200;
return structure; // here structure is {status: 200, message: 'registered'|'login', user: document}
});
Also, note that using the syntax shortcut (without curly braces around the function body) for arrow functions implies the one-line body is returned:
singleArgument => doSomething();
// is actually *strictly* equivalent to
(singleArgument) => { return doSomething(); }
With these ways of writing, it's easy to lose the reflex of writing return when it's needed.
I'm using firestore to retrieve data which has the following DS.
I have a Company collection which contains a subcollection Branches
So I'm trying to retrieve to list all the Companies with its Branches
Code:
exports.findAll = function (req, res) {
getcompanies().
then((companies) => {
console.log("Main "+ companies) // info: Main TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined
return res.json(companies);
})
.catch((err) => {
console.log('Error getting documents', err);
});
}
function getCompanies(){
var companiesRef = db.collection('companies');
return companiesRef.get()
.then((snapshot) => {
let companies = [];
return Promise.all(
snapshot.forEach(doc => {
let company = {};
company.id = doc.id;
company.company = doc.data();
var branchesPromise = getBranchesForCompanyById(company.id);
return branchesPromise.then((branches) => {
company.branches = branches;
companies.push(company);
if(snapshot.size === companies.length){
console.log("companies - Inside" + JSON.stringify(companies)); //This prints all companies with its branches
}
return Promise.resolve(companies);
})
.catch(err => {
console.log("Error getting sub-collection documents", err);
return Promise.reject(err);
})
})
)
.then(companies => {
console.log("Outside " + companies) // This is never executed
return companies;
})
.catch(err => {
return err;
});
})
.catch(err => {
return err;
});
}
function getBranchesForCompanyById(id){
var branchesRef = db.collection('companies').doc(id).collection('branches');
let branches = [];
return branchesRef.get()
.then(snapshot => {
snapshot.forEach(brnch => {
let branch = {};
branch.id = brnch.id;
branch.branch = brnch.data();
branches.push(branch);
})
return branches;
})
.catch(err => {
return err;
})
}
I've all the data needed at this point.
console.log("companies - Inside" + JSON.stringify(companies)); //This prints all companies with its branches
But the then of Promise.all is never executed. So getting this error -
info: Main TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined
console.log("Main "+ companies) // info: Main TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined
I feel I have followed all the rules specified here: https://stackoverflow.com/a/31414472/2114024 with respect to nested promises, not sure where I'm missing the point.
Thanks in advance!
I see at least 2 problems:
forEach likely doesn't return anything, and you send the result of forEach into Promise.all().
If Promise.all() throws an exception, some of your catch handlers just grab the error and return it. Returning it turns it into a non-exception.
You also really don't have to add a catch to every Promise chain, as long as you feed the result of a Promise chain back into another promise chain, you probably only need 1 catch block.
Also one of your then() functions should not be nested as deeply. Just move it a level up, that's the point of promises.
In your code, you can use map instead of forEach. Promise.all accept an array of promises but forEach does not return an array
return Promise.all(
snapshot.map(doc => {
let company = {};
company.id = doc.id;
company.company = doc.data();
var branchesPromise = getBranchesForCompanyById(company.id);
return branchesPromise.then((branches) => {
company.branches = branches;
companies.push(company);
if (snapshot.size === companies.length) {
console.log("companies - Inside" + JSON.stringify(companies)); //This prints all companies with its branches
}
return Promise.resolve(companies);
})
.catch(err => {
console.log("Error getting sub-collection documents", err);
return Promise.reject(err);
})
})
)
Based on inputs from Evert and Rahul, thanks to both of you, I have resolved the problem here.
I handled all the error in the catch block
Promise.all was not returning anything so I converted the forEach to map.
So this is my updated code, which solves the problem:
exports.findAll = function (req, res) {
getcompanies().
then((companies) => {
console.log("Main " + companies) // Prints all companies with its branches
return res.json(companies);
})
.catch((err) => {
console.log('Error getting documents', err);
return res.status(500).json({ message: "Error getting the all companies" + err });
});
}
function getCompanies() {
var companiesRef = db.collection('companies');
return companiesRef.get()
.then((snapshot) => {
let companies = [];
return Promise.all(
snapshot.docs.map(doc => {
let company = {};
company.id = doc.id;
company.company = doc.data();
var branchesPromise = getBranchesForCompanyById(company.id);
return branchesPromise.then((branches) => {
company.branches = branches;
companies.push(company);
if (snapshot.size === companies.length) {
console.log("companies - Inside" + JSON.stringify(companies));
return companies;
}
})
.catch(err => {
console.log("Error getting sub-collection documents", err);
throw new Error(err);
})
})
)
.then(companies => {
console.log("Outside " + companies); // Executed now
return companies[companies.length - 1];
})
.catch(err => {
throw new Error(err);
});
})
.catch(err => {
throw new Error(err);
});
}
function getBranchesForCompanyById(id) {
var branchesRef = db.collection('companies').doc(id).collection('branches');
let branches = [];
return branchesRef.get()
.then(snapshot => {
snapshot.forEach(brnch => {
let branch = {};
branch.id = brnch.id;
branch.branch = brnch.data();
branches.push(branch);
})
return branches;
})
.catch(err => {
throw new Error(err);
})
}