Skip to content

Commit 4dfc896

Browse files
moritzrahorabbah
andauthored
Support client retries (#227)
* Support client retries * typo * Update README.md with Rodric's suggestion Co-authored-by: rodric rabbah <[email protected]> * add no retry test + fix test nock race conditions * retry spy + test no retry on success * trigger travis build * install only production dependencies for nnewer npm versionns * back to old npm prod install + increase size too 2k * actually let s try to update the npm prod install Co-authored-by: rodric rabbah <[email protected]>
1 parent 117cd4f commit 4dfc896

File tree

6 files changed

+276
-16
lines changed

6 files changed

+276
-16
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ _Client constructor supports the following mandatory parameters:_
105105
- **key**. Client key to use when connecting to the `apihost` (if `nginx_ssl_verify_client` is turned on in your apihost)
106106
- **proxy.** HTTP(s) URI for proxy service to forwards requests through. Uses Needle's [built-in proxy support](https://github.com/tomas/needle#request-options).
107107
- **agent.** Provide custom [http.Agent](https://nodejs.org/api/http.html#http_class_http_agent) implementation.
108-
108+
- **retry**. Provide a retry options to retry on errors, for example, `{ retries: 2 }`. By default, no retries will be done. Uses [async-retry options](https://github.com/vercel/async-retry#api). Default values are different from async-retry, please refer to the API doc.
109109

110110
### environment variables
111111

lib/client.js

+40-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const OpenWhiskError = require('./openwhisk_error')
2222
const needle = require('needle')
2323
const url = require('url')
2424
const http = require('http')
25+
const retry = require('async-retry')
2526

2627
/**
2728
* This implements a request-promise-like facade over the needle
@@ -77,6 +78,13 @@ const rp = opts => {
7778
})
7879
}
7980

81+
const rpWithRetry = opts => {
82+
return retry(bail => {
83+
// will retry on exception
84+
return rp(opts)
85+
}, opts.retry)
86+
}
87+
8088
class Client {
8189
/**
8290
* @constructor
@@ -93,6 +101,13 @@ class Client {
93101
* @param {boolean} [options.noUserAgent]
94102
* @param {string} [options.cert]
95103
* @param {string} [options.key]
104+
* @param {object} [options.retry]
105+
* @param {number} [options.retry.retries] Number of retries on top of the initial request, default is 2.
106+
* @param {number} [options.retry.factor] Exponential factor, default is 2.
107+
* @param {number} [options.retry.minTimeout] Milliseconds before the first retry, default is 100.
108+
* @param {number} [options.retry.maxTimeout] Max milliseconds in between two retries, default is infinity.
109+
* @param {boolean} [options.retry.randomize] Randomizes the timeouts by multiplying with a factor between 1 to 2. Default is true.
110+
* @param {Function} [options.retry.onRetry] An optional function that is invoked after a new retry is performed. It's passed the Error that triggered it as a parameter.
96111
*/
97112
constructor (options) {
98113
this.options = this.parseOptions(options || {})
@@ -135,7 +150,21 @@ class Client {
135150
throw new Error(`${messages.INVALID_OPTIONS_ERROR} Missing either api or apihost parameters.`)
136151
}
137152

138-
return { apiKey: apiKey, api, apiVersion: apiversion, ignoreCerts: ignoreCerts, namespace: options.namespace, apigwToken: apigwToken, apigwSpaceGuid: apigwSpaceGuid, authHandler: options.auth_handler, noUserAgent: options.noUserAgent, cert: options.cert, key: options.key, proxy, agent }
153+
// gather retry options
154+
const retry = options.retry
155+
if (retry && typeof options.retry !== 'object') {
156+
throw new Error(`${messages.INVALID_OPTIONS_ERROR} 'retry' option must be an object, e.g. '{ retries: 2 }'.`)
157+
}
158+
if (retry) {
159+
// overwrite async-retry defaults, see https://github.com/vercel/async-retry#api for more details
160+
retry.retries = retry.retries || 2
161+
retry.factor = retry.factor || 2
162+
retry.minTimeout = retry.minTimeout || 100
163+
retry.maxTimeout = retry.maxTimeout || Infinity
164+
retry.randomize = retry.randomize || true
165+
}
166+
167+
return { apiKey: apiKey, api, apiVersion: apiversion, ignoreCerts: ignoreCerts, namespace: options.namespace, apigwToken: apigwToken, apigwSpaceGuid: apigwSpaceGuid, authHandler: options.auth_handler, noUserAgent: options.noUserAgent, cert: options.cert, key: options.key, proxy, agent, retry }
139168
}
140169

141170
urlFromApihost (apihost, apiversion = 'v1') {
@@ -152,7 +181,12 @@ class Client {
152181

153182
request (method, path, options) {
154183
const params = this.params(method, path, options)
155-
return params.then(req => rp(req)).catch(err => this.handleErrors(err))
184+
return params.then(req => {
185+
if (req.retry) {
186+
return rpWithRetry(req)
187+
}
188+
return rp(req)
189+
}).catch(err => this.handleErrors(err))
156190
}
157191

158192
params (method, path, options) {
@@ -194,6 +228,10 @@ class Client {
194228
parms.agent = this.options.agent
195229
}
196230

231+
if (this.options.retry) {
232+
parms.retry = this.options.retry
233+
}
234+
197235
return parms
198236
})
199237
}

package-lock.json

+152-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"coverage:integration": "nyc --no-clean --silent npm run test:integration",
1919
"coverage:report": "nyc report --reporter=lcov --reporter=text-summary",
2020
"coverage:upload": "codecov",
21-
"check-deps-size": "./tools/check_size.sh 1100",
21+
"check-deps-size": "./tools/check_size.sh 2000",
2222
"lint": "standard"
2323
},
2424
"repository": {
@@ -47,9 +47,11 @@
4747
"nock": "^11.7.0",
4848
"nyc": "^14.1.1",
4949
"pre-commit": "^1.2.2",
50+
"sinon": "^11.1.2",
5051
"standard": "^12.0.1"
5152
},
5253
"dependencies": {
54+
"async-retry": "^1.3.3",
5355
"needle": "^2.4.0"
5456
}
5557
}

0 commit comments

Comments
 (0)