Skip to content

Commit 7955095

Browse files
authored
Merge ac24ef8 into dbd54f7
2 parents dbd54f7 + ac24ef8 commit 7955095

File tree

2 files changed

+32
-7
lines changed

2 files changed

+32
-7
lines changed

.changeset/cool-toys-marry.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@firebase/functions": patch
3+
---
4+
5+
Clear pending timeout after promise.race. It allows the process to exit immediately in case the SDK is used in Node.js, otherwise the process will wait for the timeout to finish before exiting.

packages/functions/src/service.ts

+27-7
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,34 @@ export interface HttpResponseBody {
5353
};
5454
}
5555

56+
interface CancellablePromise<T> {
57+
promise: Promise<T>;
58+
cancel: () => void;
59+
}
60+
5661
/**
5762
* Returns a Promise that will be rejected after the given duration.
5863
* The error will be of type FunctionsError.
5964
*
6065
* @param millis Number of milliseconds to wait before rejecting.
6166
*/
62-
function failAfter(millis: number): Promise<never> {
63-
return new Promise((_, reject) => {
64-
setTimeout(() => {
65-
reject(new FunctionsError('deadline-exceeded', 'deadline-exceeded'));
66-
}, millis);
67-
});
67+
function failAfter(millis: number): CancellablePromise<never> {
68+
// Node timers and browser timers are fundamentally incompatible, but we
69+
// don't care about the value here
70+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
71+
let timer: any | null = null;
72+
return {
73+
promise: new Promise((_, reject) => {
74+
timer = setTimeout(() => {
75+
reject(new FunctionsError('deadline-exceeded', 'deadline-exceeded'));
76+
}, millis);
77+
}),
78+
cancel: () => {
79+
if (timer) {
80+
clearTimeout(timer);
81+
}
82+
}
83+
};
6884
}
6985

7086
/**
@@ -247,12 +263,16 @@ async function call(
247263
// Default timeout to 70s, but let the options override it.
248264
const timeout = options.timeout || 70000;
249265

266+
const failAfterHandle = failAfter(timeout);
250267
const response = await Promise.race([
251268
postJSON(url, body, headers, functionsInstance.fetchImpl),
252-
failAfter(timeout),
269+
failAfterHandle.promise,
253270
functionsInstance.cancelAllRequests
254271
]);
255272

273+
// Always clear the failAfter timeout
274+
failAfterHandle.cancel();
275+
256276
// If service was deleted, interrupted response throws an error.
257277
if (!response) {
258278
throw new FunctionsError(

0 commit comments

Comments
 (0)