Skip to content

Commit ff4a3ef

Browse files
authored
Merge d439ded into 064cf2e
2 parents 064cf2e + d439ded commit ff4a3ef

File tree

5 files changed

+50
-11
lines changed

5 files changed

+50
-11
lines changed

.changeset/nasty-pigs-invite.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@firebase/functions": patch
3+
"firebase": patch
4+
---
5+
6+
Clear timeout after a successful response or after the request is canceled. Fixes [issue 3289](https://github.com/firebase/firebase-js-sdk/issues/3289).

config/functions/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
},
99
"private": true,
1010
"engines": {
11-
"node": "8"
11+
"node": "10"
1212
}
1313
}

packages/functions/src/api/service.ts

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,23 @@ export interface HttpResponseBody {
5858
*
5959
* @param millis Number of milliseconds to wait before rejecting.
6060
*/
61-
function failAfter(millis: number): Promise<never> {
62-
return new Promise((_, reject) => {
63-
setTimeout(() => {
61+
function failAfter(
62+
millis: number
63+
): {
64+
timer: number | NodeJS.Timeout;
65+
promise: Promise<never>;
66+
} {
67+
let timer!: number | NodeJS.Timeout;
68+
const promise = new Promise<never>((_, reject) => {
69+
timer = setTimeout(() => {
6470
reject(new HttpsErrorImpl('deadline-exceeded', 'deadline-exceeded'));
6571
}, millis);
6672
});
73+
74+
return {
75+
timer,
76+
promise
77+
};
6778
}
6879

6980
/**
@@ -213,10 +224,12 @@ export class Service implements FirebaseFunctions, FirebaseService {
213224
// Default timeout to 70s, but let the options override it.
214225
const timeout = options.timeout || 70000;
215226

227+
const { timer, promise: failAfterPromise } = failAfter(timeout);
228+
216229
const response = await Promise.race([
217-
this.postJSON(url, body, headers),
218-
failAfter(timeout),
219-
this.cancelAllRequests
230+
clearTimeoutWrapper(timer, this.postJSON(url, body, headers)),
231+
failAfterPromise,
232+
clearTimeoutWrapper(timer, this.cancelAllRequests)
220233
]);
221234

222235
// If service was deleted, interrupted response throws an error.
@@ -261,3 +274,13 @@ export class Service implements FirebaseFunctions, FirebaseService {
261274
return { data: decodedData };
262275
}
263276
}
277+
278+
async function clearTimeoutWrapper<T>(
279+
timer: number | NodeJS.Timeout,
280+
promise: Promise<T>
281+
): Promise<T> {
282+
const result = await promise;
283+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
284+
clearTimeout(timer as any);
285+
return result;
286+
}

packages/functions/test/callable.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,4 +190,14 @@ describe('Firebase Functions > Call', () => {
190190
const func = functions.httpsCallable('timeoutTest', { timeout: 10 });
191191
await expectError(func(), 'deadline-exceeded', 'deadline-exceeded');
192192
});
193+
194+
it('cancels timeout', async () => {
195+
const functions = createTestService(app, region);
196+
const globalObj = typeof window !== 'undefined' ? window : global;
197+
const clearTimeoutSpy = sinon.spy(globalObj, 'clearTimeout');
198+
const func = functions.httpsCallable('nullTest');
199+
await func(null);
200+
expect(clearTimeoutSpy.called).to.be.true;
201+
clearTimeoutSpy.restore();
202+
});
193203
});

tools/config.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @license
3-
* Copyright 2017 Google Inc.
3+
* Copyright 2017 Google LLC
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -72,12 +72,12 @@ Promise.resolve(userToken || cachedToken)
7272
})();
7373

7474
// Write config to top-level config directory
75-
await firebaseTools.setup
76-
.web({ project, token })
75+
await firebaseTools.apps
76+
.sdkconfig('web', undefined, { project, token })
7777
.then(config =>
7878
fs.writeFile(
7979
path.resolve(__dirname, '../config/project.json'),
80-
JSON.stringify(config, null, 2)
80+
JSON.stringify(config.sdkConfig, null, 2)
8181
)
8282
);
8383

0 commit comments

Comments
 (0)