Skip to content

Commit 2aae868

Browse files
jasnelltargos
authored andcommitted
timers: propagate signal.reason in awaitable timers
Signed-off-by: James M Snell <[email protected]> PR-URL: #41008 Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Robert Nagy <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]>
1 parent 90f395d commit 2aae868

4 files changed

+37
-8
lines changed

lib/timers/promises.js

+11-8
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const kScheduler = Symbol('kScheduler');
4444
function cancelListenerHandler(clear, reject, signal) {
4545
if (!this._destroyed) {
4646
clear(this);
47-
reject(new AbortError());
47+
reject(new AbortError(undefined, { cause: signal?.reason }));
4848
}
4949
}
5050

@@ -74,15 +74,15 @@ function setTimeout(after, value, options = kEmptyObject) {
7474
// to 12.x, then this can be converted to use optional chaining to
7575
// simplify the check.
7676
if (signal && signal.aborted) {
77-
return PromiseReject(new AbortError());
77+
return PromiseReject(new AbortError(undefined, { cause: signal.reason }));
7878
}
7979
let oncancel;
8080
const ret = new Promise((resolve, reject) => {
8181
const timeout = new Timeout(resolve, after, args, false, ref);
8282
insert(timeout, timeout._idleTimeout);
8383
if (signal) {
8484
oncancel = FunctionPrototypeBind(cancelListenerHandler,
85-
timeout, clearTimeout, reject);
85+
timeout, clearTimeout, reject, signal);
8686
signal.addEventListener('abort', oncancel);
8787
}
8888
});
@@ -117,15 +117,16 @@ function setImmediate(value, options = kEmptyObject) {
117117
// to 12.x, then this can be converted to use optional chaining to
118118
// simplify the check.
119119
if (signal && signal.aborted) {
120-
return PromiseReject(new AbortError());
120+
return PromiseReject(new AbortError(undefined, { cause: signal.reason }));
121121
}
122122
let oncancel;
123123
const ret = new Promise((resolve, reject) => {
124124
const immediate = new Immediate(resolve, [value]);
125125
if (!ref) immediate.unref();
126126
if (signal) {
127127
oncancel = FunctionPrototypeBind(cancelListenerHandler,
128-
immediate, clearImmediate, reject);
128+
immediate, clearImmediate, reject,
129+
signal);
129130
signal.addEventListener('abort', oncancel);
130131
}
131132
});
@@ -142,7 +143,7 @@ async function* setInterval(after, value, options = kEmptyObject) {
142143
validateBoolean(ref, 'options.ref');
143144

144145
if (signal?.aborted)
145-
throw new AbortError();
146+
throw new AbortError(undefined, { cause: signal?.reason });
146147

147148
let onCancel;
148149
let interval;
@@ -161,7 +162,9 @@ async function* setInterval(after, value, options = kEmptyObject) {
161162
onCancel = () => {
162163
clearInterval(interval);
163164
if (callback) {
164-
callback(PromiseReject(new AbortError()));
165+
callback(
166+
PromiseReject(
167+
new AbortError(undefined, { cause: signal.reason })));
165168
callback = undefined;
166169
}
167170
};
@@ -176,7 +179,7 @@ async function* setInterval(after, value, options = kEmptyObject) {
176179
yield value;
177180
}
178181
}
179-
throw new AbortError();
182+
throw new AbortError(undefined, { cause: signal?.reason });
180183
} finally {
181184
clearInterval(interval);
182185
signal?.removeEventListener('abort', onCancel);

test/parallel/test-timers-immediate-promisified.js

+7
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,10 @@ process.on('multipleResolves', common.mustNotCall());
9797
assert.strictEqual(stderr, '');
9898
}));
9999
}
100+
101+
(async () => {
102+
const signal = AbortSignal.abort('boom');
103+
await assert.rejects(timerPromises.setImmediate(undefined, { signal }), {
104+
cause: 'boom',
105+
});
106+
})().then(common.mustCall());

test/parallel/test-timers-interval-promisified.js

+12
Original file line numberDiff line numberDiff line change
@@ -246,3 +246,15 @@ process.on('multipleResolves', common.mustNotCall());
246246
setPromiseTimeout(time_unit * 3).then(() => post = true),
247247
]).then(common.mustCall());
248248
}
249+
250+
(async () => {
251+
const signal = AbortSignal.abort('boom');
252+
try {
253+
const iterable = timerPromises.setInterval(2, undefined, { signal });
254+
// eslint-disable-next-line no-unused-vars, no-empty
255+
for await (const _ of iterable) { }
256+
assert.fail('should have failed');
257+
} catch (err) {
258+
assert.strictEqual(err.cause, 'boom');
259+
}
260+
})().then(common.mustCall());

test/parallel/test-timers-timeout-promisified.js

+7
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,10 @@ process.on('multipleResolves', common.mustNotCall());
9797
assert.strictEqual(stderr, '');
9898
}));
9999
}
100+
101+
(async () => {
102+
const signal = AbortSignal.abort('boom');
103+
await assert.rejects(timerPromises.setTimeout(1, undefined, { signal }), {
104+
cause: 'boom',
105+
});
106+
})().then(common.mustCall());

0 commit comments

Comments
 (0)