Skip to content
This repository was archived by the owner on Jan 17, 2025. It is now read-only.

Commit 67b6449

Browse files
authored
Added Promise-with-expiration support for needle requests (#20)
* Added Promise-with-expiration support for needle requests * Bump version to 1.0.6
1 parent 21996ff commit 67b6449

File tree

4 files changed

+46
-4
lines changed

4 files changed

+46
-4
lines changed

__tests__/tokens.spec.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,16 @@ test('should call requestToken() only once with many parallel getAuthHeader() ca
3636
spy2.mockRestore()
3737
})
3838
})
39+
test('should properly timeout on network slowness', () => {
40+
jest.setTimeout(120000)
41+
needle.mockResolvedValue(new Promise((resolve) => {
42+
setTimeout(() => { resolve(validToken) }, 100000) // current limit is 90000 for the Promise timeout
43+
}))
44+
return tm.getAuthHeader()
45+
.then(resp => {
46+
jest.fail('Got response, but expected an Error')
47+
})
48+
.catch(err => {
49+
expect(err).toEqual(new Error('Promise timed out after 90000 milliseconds.'))
50+
})
51+
})

index.js

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,28 @@ module.exports = class TokenManager {
2525
throw new Error(`Missing iamApikey parameter.`)
2626
}
2727
}
28+
29+
// wraps a promise with a promise that supports timing out after a given amount of
30+
// milliseconds. Wrapping promise throws, when the timeout occurs.
31+
getPromiseWithExpiration (prom, timeout) {
32+
let timeoutHandle
33+
34+
return new Promise((resolve, reject) => {
35+
timeoutHandle = setTimeout(() => {
36+
reject(new Error('Promise timed out after ' + timeout + ' milliseconds.'))
37+
}, timeout)
38+
39+
prom.then((result) => {
40+
clearTimeout(timeoutHandle)
41+
resolve(result)
42+
})
43+
.catch((error) => {
44+
clearTimeout(timeoutHandle)
45+
reject(error)
46+
})
47+
})
48+
}
49+
2850
/**
2951
* This function sends an access token back through a Promise. The source of the token
3052
* is determined by the following logic:
@@ -204,7 +226,9 @@ module.exports = class TokenManager {
204226
* @returns {Promise}
205227
*/
206228
sendRequest (options) {
207-
return needle(options.method.toLowerCase(),
229+
options.response_timeout = 60000 // 1 minute max. response time allowed
230+
options.read_timeout = 30000 // 30 seconds read time limit after headers were received
231+
const needleProm = needle(options.method.toLowerCase(),
208232
options.url,
209233
options.body || qs.stringify(options.form),
210234
options)
@@ -218,11 +242,16 @@ module.exports = class TokenManager {
218242
if (typeof error.error === 'object') {
219243
error.error.error = error.error.errorMessage
220244
}
221-
return Promise.reject(error)
245+
throw error // this will trigger the next available catch() in the Promise chain
222246
} else {
223247
// otherwise, the response body is the expected return value
224248
return resp.body
225249
}
226250
})
251+
252+
// wrap the actual loading promise which allows the HTTP request to take 60 seconds
253+
// with a promise that times out after 90 seconds, so we don't get stuck with an
254+
// unsettled promise
255+
return this.getPromiseWithExpiration(needleProm, 90000)
227256
}
228257
}

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@ibm-functions/iam-token-manager",
3-
"version": "1.0.5",
3+
"version": "1.0.6",
44
"description": "Helper library to handle IBM Cloud IAM Tokens",
55
"main": "index.js",
66
"files": [

0 commit comments

Comments
 (0)