Skip to content

Commit 506a1cb

Browse files
jBarzitaloacasas
authored andcommitted
timer,domain: maintain order of timer callbacks
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>
1 parent 6a45265 commit 506a1cb

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

lib/timers.js

+15
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,19 @@ function TimersList(msecs, unrefed) {
156156
this._timer = new TimerWrap();
157157
this._unrefed = unrefed;
158158
this.msecs = msecs;
159+
this.nextTick = false;
159160
}
160161

161162
function listOnTimeout() {
162163
var list = this._list;
163164
var msecs = list.msecs;
164165

166+
if (list.nextTick) {
167+
list.nextTick = false;
168+
process.nextTick(listOnTimeoutNT, list);
169+
return;
170+
}
171+
165172
debug('timeout callback %d', msecs);
166173

167174
var now = TimerWrap.now();
@@ -239,6 +246,14 @@ function tryOnTimeout(timer, list) {
239246
} finally {
240247
if (!threw) return;
241248

249+
// Postpone all later list events to next tick. We need to do this
250+
// so that the events are called in the order they were created.
251+
const lists = list._unrefed === true ? unrefedLists : refedLists;
252+
for (var key in lists) {
253+
if (key > list.msecs) {
254+
lists[key].nextTick = true;
255+
}
256+
}
242257
// We need to continue processing after domain error handling
243258
// is complete, but not by using whatever domain was left over
244259
// when the timeout threw its exception.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict';
2+
const common = require('../common');
3+
4+
// This test ensures that the timer callbacks are called in the order in which
5+
// they were created in the event of an unhandled exception in the domain.
6+
7+
const domain = require('domain').create();
8+
const assert = require('assert');
9+
10+
let first = false;
11+
12+
domain.run(function() {
13+
setTimeout(() => { throw new Error('FAIL'); }, 1);
14+
setTimeout(() => { first = true; }, 1);
15+
setTimeout(() => { assert.strictEqual(first, true); }, 2);
16+
17+
// Ensure that 2 ms have really passed
18+
let i = 1e6;
19+
while (i--);
20+
});
21+
22+
domain.once('error', common.mustCall((err) => {
23+
assert(err);
24+
assert.strictEqual(err.message, 'FAIL');
25+
}));

0 commit comments

Comments
 (0)