Skip to content

Commit

Permalink
timer,domain: maintain order of timer callbacks
Browse files Browse the repository at this point in the history
PR-URL: #10522
Fixes: #1271
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
  • Loading branch information
jBarz authored and italoacasas committed Feb 22, 2017
1 parent 6a45265 commit 506a1cb
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 0 deletions.
15 changes: 15 additions & 0 deletions lib/timers.js
Expand Up @@ -156,12 +156,19 @@ function TimersList(msecs, unrefed) {
this._timer = new TimerWrap();
this._unrefed = unrefed;
this.msecs = msecs;
this.nextTick = false;
}

function listOnTimeout() {
var list = this._list;
var msecs = list.msecs;

if (list.nextTick) {
list.nextTick = false;
process.nextTick(listOnTimeoutNT, list);
return;
}

debug('timeout callback %d', msecs);

var now = TimerWrap.now();
Expand Down Expand Up @@ -239,6 +246,14 @@ function tryOnTimeout(timer, list) {
} finally {
if (!threw) return;

// Postpone all later list events to next tick. We need to do this
// so that the events are called in the order they were created.
const lists = list._unrefed === true ? unrefedLists : refedLists;
for (var key in lists) {
if (key > list.msecs) {
lists[key].nextTick = true;
}
}
// We need to continue processing after domain error handling
// is complete, but not by using whatever domain was left over
// when the timeout threw its exception.
Expand Down
25 changes: 25 additions & 0 deletions test/parallel/test-domain-timers-uncaught-exception.js
@@ -0,0 +1,25 @@
'use strict';
const common = require('../common');

// This test ensures that the timer callbacks are called in the order in which
// they were created in the event of an unhandled exception in the domain.

const domain = require('domain').create();
const assert = require('assert');

let first = false;

domain.run(function() {
setTimeout(() => { throw new Error('FAIL'); }, 1);
setTimeout(() => { first = true; }, 1);
setTimeout(() => { assert.strictEqual(first, true); }, 2);

// Ensure that 2 ms have really passed
let i = 1e6;
while (i--);
});

domain.once('error', common.mustCall((err) => {
assert(err);
assert.strictEqual(err.message, 'FAIL');
}));

0 comments on commit 506a1cb

Please sign in to comment.