Fixes asynchronous cron bug that allows cron to run twice for a user within seconds. (#10142)

* Fixes asynchronous cron bug that allows cron to run twice for a user within seconds of eachother.

fixes #8991

* Fixing tests.

* Updating assignment to keep user and res.locals.user in sync.
This commit is contained in:
Travis
2018-06-14 11:47:44 -07:00
committed by Keith Holliday
parent 6a767ed70b
commit 4044432fad
2 changed files with 22 additions and 6 deletions

View File

@@ -166,11 +166,14 @@ describe('cron middleware', () => {
await new Promise((resolve, reject) => {
cronMiddleware(req, res, (err) => {
if (err) return reject(err);
expect(user.stats.hp).to.be.lessThan(hpBefore);
User.findOne({_id: user._id}, function (secondErr, updatedUser) {
if (secondErr) return reject(secondErr);
expect(updatedUser.stats.hp).to.be.lessThan(hpBefore);
resolve();
});
});
});
});
it('updates tasks', async () => {
user.lastCron = moment(new Date()).subtract({days: 2});
@@ -217,11 +220,14 @@ describe('cron middleware', () => {
await new Promise((resolve, reject) => {
cronMiddleware(req, res, (err) => {
if (err) return reject(err);
expect(user.stats.hp).to.be.lessThan(hpBefore);
User.findOne({_id: user._id}, function (secondErr, updatedUser) {
if (secondErr) return reject(secondErr);
expect(updatedUser.stats.hp).to.be.lessThan(hpBefore);
resolve();
});
});
});
});
it('recovers from failed cron and does not error when user is already cronning', async () => {
user.lastCron = moment(new Date()).subtract({days: 2});

View File

@@ -23,7 +23,6 @@ async function checkForActiveCron (user, now) {
}, {
$set: {
_cronSignature,
lastCron: now, // setting lastCron now so we don't risk re-running parts of cron if it fails
'auth.timestamps.loggedin': now,
},
}).exec();
@@ -35,6 +34,14 @@ async function checkForActiveCron (user, now) {
}
}
async function updateLastCron (user, now) {
await User.update({
_id: user._id,
}, {
lastCron: now, // setting lastCron now so we don't risk re-running parts of cron if it fails
}).exec();
}
async function unlockUser (user) {
await User.update({
_id: user._id,
@@ -51,9 +58,12 @@ async function cronAsync (req, res) {
let now = new Date();
try {
await checkForActiveCron(user, now);
user = res.locals.user = await User.findOne({_id: user._id}).exec();
let {daysMissed, timezoneOffsetFromUserPrefs} = user.daysUserHasMissed(now, req);
await checkForActiveCron(user, now);
await updateLastCron(user, now);
if (daysMissed <= 0) {
if (user.isModified()) await user.save();