@mimik/request-retry 1.0.1 → 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc CHANGED
@@ -1,17 +1,29 @@
1
- // Use this file as a starting point for your project's .eslintrc.
2
- // Copy this file, and add rule overrides as needed.
3
1
  {
2
+ "plugins": [
3
+ "@mimik/document-env",
4
+ "@mimik/dependencies"
5
+ ],
4
6
  "env": {
5
7
  "node": true
6
8
  },
9
+ "parserOptions": {
10
+ "ecmaVersion": 2020
11
+ },
7
12
  "extends": "airbnb",
8
13
  "rules": {
14
+ "import/no-extraneous-dependencies": ["error", {"devDependencies": true}],
9
15
  "brace-style": [1, "stroustrup", {"allowSingleLine": true}],
10
- "no-confusing-arrow": [0],
16
+ "no-confusing-arrow": [0], // arrow isnt confusing
11
17
  "max-len": [1, 180, { "ignoreComments": true }],
12
18
  "linebreak-style": 0,
13
19
  "quotes": [1, "single"],
14
- "semi": [1, "always"]
20
+ "semi": [1, "always"],
21
+ "no-process-env": ["error"],
22
+ "@mimik/document-env/validate-document-env": 2,
23
+ "@mimik/dependencies/case-sensitive": 2,
24
+ "@mimik/dependencies/no-cycles": 2,
25
+ "@mimik/dependencies/no-unresolved": 2,
26
+ "@mimik/dependencies/require-json-ext": 2
15
27
  },
16
28
  "settings":{
17
29
  "react": {
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+ . "$(dirname "$0")/_/husky.sh"
3
+
4
+ npm run commit-ready
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+ . "$(dirname "$0")/_/husky.sh"
3
+
4
+ npm run test
package/Gulpfile.js CHANGED
@@ -17,14 +17,13 @@ const files = [
17
17
  const createDocs = (done) => {
18
18
  jsdoc2md.render({ files: 'index.js' })
19
19
  .then((output) => fs.writeFileSync('README.md', output))
20
- .catch((err) => log.error('docs creation failed:', err.message));
21
- return done();
20
+ .catch((err) => log.error('docs creation failed:', err.message))
21
+ .finally(() => done());
22
22
  };
23
23
 
24
24
  const lint = () => gulp.src(files)
25
25
  .pipe(eslint({}))
26
- .pipe(eslint.format())
27
- .pipe(eslint.failOnError());
26
+ .pipe(eslint.format());
28
27
 
29
28
  const add = () => gulp.src('README.md')
30
29
  .pipe(git.add({ quiet: true }));
package/README.md CHANGED
@@ -15,7 +15,15 @@ Make a request with retry.
15
15
  **Category**: async
16
16
  **Throws**:
17
17
 
18
- - <code>Promise</code> Will throw an error generated by getRichError encapsulating an error generated by [request-promise](https://www.npmjs.com/package/request-promise) or a TimeoutError.
18
+ - <code>Promise</code> Will throw an error generated by `getRichError` encapsulating an error generated by [request-promise](https://www.npmjs.com/package/request-promise) or a TimeoutError.
19
+
20
+ The following environment variable are being used:
21
+
22
+ | Env variable name | Description | Default | Comments |
23
+ | ----------------- | ----------- | ------- | -------- |
24
+ | SERVER_TYPE | type of the server instance that makes the call | generic | for defining the agent
25
+ | SERVER_VERSION |version of the server instance that makes the call | 1.0 | for defining the agent
26
+ | SERVER_ID | id of the server instance that makes the call | generic | for defining the agent
19
27
 
20
28
  The following properties are added to the `options` object under the `retry` property:
21
29
  - retries `{int}`: maximum number of retries independent to the retryStrategy. The default is `2`. If the value is less than `0` the value is set to `0`, and if the value is more that `15` the value is set to `15`,
@@ -38,11 +46,19 @@ defaultRetry = (...args) => {
38
46
  return (statusCode && (Math.floor(statusCode / 100) === 5 || statusCode === 429)) || (!statusCode && !args[1].message.includes('Invalid URI'));
39
47
  };
40
48
  ```
49
+ If logLevel is empty, request and response will be logged as info and the response will be in response property with full details. Error on the request will generate a warning. If logLevel is not empty but not complete, logLevel will take control over default.
50
+
51
+ If not alredy set,the user agent will the set to `mimik-{serverType}/{serverVersion}/{serverId} {architecture} {node}`;
52
+
53
+ To facilitate the transition from request-promise the following action are taken on options:
54
+ - `uri` takes precednce on `url`
55
+ - `body` takes precedence on `json` if `json` is an object and are used to assign `data`
56
+ - `qs` is used to assign to `params`
41
57
 
42
58
  **Requires**: <code>module:@mimik/sumologic-winston-logger</code>, <code>module:@mimik/response-helper</code>
43
- **Fulfil**: <code>object</code> - Response of the [request-promise](https://www.npmjs.com/package/request-promise) request.
59
+ **Fulfil**: <code>object</code> - Response of the [axios](https://www.npmjs.com/package/axios) response with option `resolveWithFullResponse` set to true otherwise only `response.data` is returned.
44
60
 
45
61
  | Param | Type | Description |
46
62
  | --- | --- | --- |
47
- | options | <code>object</code> | Options for the request. Similar to [request-promise](https://www.npmjs.com/package/request-promise) options. |
63
+ | options | <code>object</code> | Options for the request. Similar to [axios](https://www.npmjs.com/package/axios) options. `validateStatus` options is disabled, an error will be created for statusCode outside of [200, 300[. The options `resolveWithFullResponse` is added and if set to true, the response will be a full axios response. If set to false or missing only `reponse.data` will be returned. |
48
64
 
package/index.js CHANGED
@@ -1,15 +1,28 @@
1
- const rp = require('request-promise');
1
+ /* eslint no-process-env: "off" */
2
2
  const Promise = require('bluebird');
3
+ const axios = require('axios');
3
4
 
4
5
  const logger = require('@mimik/sumologic-winston-logger');
5
6
  const { getRichError } = require('@mimik/response-helper');
6
-
7
+ const { getCorrelationId } = require('@mimik/request-helper');
7
8
  const {
8
9
  validateOptions,
9
10
  calculateDelay,
10
11
  isRetry,
11
12
  setResponse,
12
13
  } = require('./lib/validate');
14
+ const { rp } = require('./lib/rp-axios-wrapper');
15
+
16
+ const DEFAULT_RESPONSE_NAME = 'response';
17
+ const DEFAULT_LOGLEVEL_DETAILS = 'full';
18
+ const DEFAULT_LOGLEVEL_RESPONSE = 'info';
19
+ const DEFAULT_LOGLEVEL_ERROR = 'warn';
20
+ const DEFAULT_LOGLEVEL_REQUEST = 'info';
21
+
22
+ const nodeDescription = `${process.release.name} ${process.version} ${process.release.lts}`;
23
+ const serverDescription = `mimik-${process.env.SERVER_TYPE || 'generic'}/${process.env.SERVER_VERSION || '1.0'}/${process.env.SERVER_ID || 'generic'}`;
24
+ const platformDescription = `${process.platform}; ${process.arch}`;
25
+ const userAgent = `${serverDescription} (${platformDescription}; ${nodeDescription})`;
13
26
 
14
27
  Promise.config({ cancellation: true });
15
28
 
@@ -26,10 +39,18 @@ Promise.config({ cancellation: true });
26
39
  * @requires @mimik/sumologic-winston-logger
27
40
  * @requires @mimik/response-helper
28
41
  * @category async
29
- * @param {object} options - Options for the request. Similar to [request-promise](https://www.npmjs.com/package/request-promise) options.
42
+ * @param {object} options - Options for the request. Similar to [axios](https://www.npmjs.com/package/axios) options. `validateStatus` options is disabled, an error will be created for statusCode outside of [200, 300[. The options `resolveWithFullResponse` is added and if set to true, the response will be a full axios response. If set to false or missing only `reponse.data` will be returned.
30
43
  * @return {Promise}.
31
- * @fulfil {object} - Response of the [request-promise](https://www.npmjs.com/package/request-promise) request.
32
- * @throws {Promise} Will throw an error generated by getRichError encapsulating an error generated by [request-promise](https://www.npmjs.com/package/request-promise) or a TimeoutError.
44
+ * @fulfil {object} - Response of the [axios](https://www.npmjs.com/package/axios) response with option `resolveWithFullResponse` set to true otherwise only `response.data` is returned.
45
+ * @throws {Promise} Will throw an error generated by `getRichError` encapsulating an error generated by [request-promise](https://www.npmjs.com/package/request-promise) or a TimeoutError.
46
+ *
47
+ * The following environment variable are being used:
48
+ *
49
+ * | Env variable name | Description | Default | Comments |
50
+ * | ----------------- | ----------- | ------- | -------- |
51
+ * | SERVER_TYPE | type of the server instance that makes the call | generic | for defining the agent
52
+ * | SERVER_VERSION |version of the server instance that makes the call | 1.0 | for defining the agent
53
+ * | SERVER_ID | id of the server instance that makes the call | generic | for defining the agent
33
54
  *
34
55
  * The following properties are added to the `options` object under the `retry` property:
35
56
  * - retries `{int}`: maximum number of retries independent to the retryStrategy. The default is `2`. If the value is less than `0` the value is set to `0`, and if the value is more that `15` the value is set to `15`,
@@ -52,32 +73,54 @@ Promise.config({ cancellation: true });
52
73
  * return (statusCode && (Math.floor(statusCode / 100) === 5 || statusCode === 429)) || (!statusCode && !args[1].message.includes('Invalid URI'));
53
74
  * };
54
75
  *```
76
+ * If logLevel is empty, request and response will be logged as info and the response will be in response property with full details. Error on the request will generate a warning. If logLevel is not empty but not complete, logLevel will take control over default.
55
77
  *
78
+ * If not alredy set,the user agent will the set to `mimik-{serverType}/{serverVersion}/{serverId} {architecture} {node}`;
79
+ *
80
+ * To facilitate the transition from request-promise the following action are taken on options:
81
+ * - `uri` takes precednce on `url`
82
+ * - `body` takes precedence on `json` if `json` is an object and are used to assign `data`
83
+ * - `qs` is used to assign to `params`
56
84
  */
57
- const rpRetry = (options) => {
58
- const correlationId = (options.headers && options.headers['x-correlation-id']);
85
+ const rpRetry = (origOptions) => {
86
+ const { CancelToken } = axios;
87
+ const source = CancelToken.source();
88
+ const options = origOptions;
89
+ const correlationId = (options.headers && options.headers['x-correlation-id']) ? options.headers['x-correlation-id'] : getCorrelationId();
59
90
  const errors = [];
60
91
  const delayPromises = [];
92
+ const criteria = validateOptions(options, correlationId);
93
+ const { logLevel } = criteria;
94
+ const logLevelLength = Object.keys(logLevel).length;
61
95
  let nbRetries = 0;
96
+ let mainTimeout;
97
+
98
+ if (!options.headers) options.headers = { 'user-agent': userAgent };
99
+ else if (!options.headers['user-agent']) options.headers['user-agent'] = userAgent;
100
+ options.cancelToken = source.token;
62
101
 
63
- const retryProcess = (opts, nbRetry, crit, corrId) => rp(opts)
102
+ const retryProcess = (nbRetry) => rp(options)
64
103
  .then((response) => {
65
- const info = { options: opts, nbRetries, errors };
104
+ const info = { options, nbRetries, errors };
66
105
 
67
- if (crit.logLevel.response) {
68
- info[crit.logLevel.responseName] = setResponse(response, crit.logLevel.responseDetails);
69
- logger[crit.logLevel.response]('request response', info, corrId);
106
+ if (logLevel.response) {
107
+ info[logLevel.responseName] = setResponse(response, logLevel.responseDetails);
108
+ logger[logLevel.response]('request response', info, correlationId);
109
+ }
110
+ else if (logLevelLength === 0) {
111
+ info[DEFAULT_RESPONSE_NAME] = setResponse(response, DEFAULT_LOGLEVEL_DETAILS);
112
+ logger[DEFAULT_LOGLEVEL_RESPONSE]('request response', info, correlationId);
70
113
  }
71
114
  return response;
72
115
  })
73
116
  .catch((err) => {
74
- if ((nbRetry < crit.retries) && isRetry(opts, nbRetry, crit, err, corrId)) {
117
+ if ((nbRetry < criteria.retries) && isRetry(options, nbRetry, criteria, err, correlationId)) {
75
118
  nbRetries = nbRetry + 1;
76
- errors.push(err.message);
77
- const delayPromise = Promise.delay(calculateDelay(opts, nbRetry, crit, err, corrId));
119
+ errors.push(err);
120
+ const delayPromise = Promise.delay(calculateDelay(options, nbRetry, criteria, err, correlationId));
78
121
 
79
122
  delayPromises.unshift(delayPromise);
80
- return delayPromise.then(() => retryProcess(opts, nbRetry + 1, crit, corrId));
123
+ return delayPromise.then(() => retryProcess(nbRetry + 1));
81
124
  }
82
125
  const error = err;
83
126
 
@@ -88,36 +131,49 @@ const rpRetry = (options) => {
88
131
  errors,
89
132
  };
90
133
  }
91
- throw getRichError(error.statusCode, 'request error response', { options }, error, crit.logLevel.error, corrId);
134
+ throw getRichError(
135
+ error.statusCode,
136
+ 'request error response',
137
+ { options },
138
+ error,
139
+ logLevel.error || ((logLevelLength === 0) ? DEFAULT_LOGLEVEL_ERROR : undefined),
140
+ correlationId,
141
+ );
92
142
  });
93
143
 
94
- let mainTimeout;
95
- const criteria = validateOptions(options);
96
- const retryPromise = retryProcess(options, 0, criteria, correlationId);
144
+ const retryPromise = retryProcess(0);
97
145
  const mainTimeoutPromise = new Promise((resolve, reject) => {
98
146
  mainTimeout = setTimeout(() => {
99
- delayPromises.forEach((delayPromise) => delayPromise.cancel());
100
- retryPromise.cancel();
147
+ delayPromises.forEach((delayPromise) => delayPromise.cancel(`retry timeout, ${criteria.timeout}, ${nbRetries}`));
148
+ source.cancel(`retry timeout, ${criteria.timeout}, ${nbRetries}`);
101
149
  let error = new Error('retry timeout');
102
150
 
103
151
  if (nbRetries !== 0) {
104
152
  error.info = { retry: { nbRetries, errors } };
105
153
  }
106
154
  error.name = 'TimeoutError';
107
- error = getRichError('System', 'request error response', { options }, error, criteria.logLevel.error, correlationId);
155
+ error = getRichError(
156
+ 'System',
157
+ 'request error response',
158
+ { options },
159
+ error,
160
+ logLevel.error || ((logLevelLength === 0) ? DEFAULT_LOGLEVEL_ERROR : undefined),
161
+ correlationId,
162
+ );
108
163
  reject(error);
109
164
  }, criteria.timeout * 1000);
110
165
  });
111
166
 
112
- if (criteria.logLevel.request) logger[criteria.logLevel.request]('making a request', { options, criteria }, correlationId);
167
+ if (logLevel.request) logger[logLevel.request]('making a request', { options, criteria }, correlationId);
168
+ else if (logLevelLength === 0) logger[DEFAULT_LOGLEVEL_REQUEST]('making a request', { options, criteria }, correlationId);
113
169
  return Promise.race([retryPromise, mainTimeoutPromise])
114
170
  .then((result) => {
115
- mainTimeoutPromise.cancel();
171
+ mainTimeoutPromise.cancel('main timeout');
116
172
  clearTimeout(mainTimeout);
117
173
  return result;
118
174
  })
119
175
  .catch((err) => {
120
- mainTimeoutPromise.cancel();
176
+ mainTimeoutPromise.cancel(`main timeout error: ${err.message}`);
121
177
  clearTimeout(mainTimeout);
122
178
  throw err;
123
179
  });
@@ -0,0 +1,48 @@
1
+ const axios = require('axios');
2
+ const _ = require('lodash');
3
+
4
+ const { getRichError } = require('@mimik/response-helper');
5
+
6
+ const rp = (origOptions) => {
7
+ const options = _.clone(origOptions);
8
+
9
+ if (options.uri) options.url = options.uri;
10
+ delete options.uri;
11
+ delete options.validateStatus;
12
+ if (options.body) {
13
+ options.data = options.body;
14
+ delete options.body;
15
+ }
16
+ else if (typeof options.json === 'object') {
17
+ options.data = options.body;
18
+ delete options.json;
19
+ }
20
+ else delete options.json;
21
+ if (options.qs) options.params = options.qs;
22
+ return axios(options)
23
+ .then((res) => {
24
+ if (options.resolveWithFullResponse) return res;
25
+ return res.data;
26
+ })
27
+ .catch((err) => {
28
+ const { response } = err;
29
+ let errorMsg = 'no response';
30
+
31
+ if (err.message) errorMsg = `${errorMsg}: ${err.message}`;
32
+ if (!response) {
33
+ throw getRichError('System', errorMsg, {
34
+ code: err.code,
35
+ address: err.address,
36
+ port: err.port,
37
+ syscall: err.syscall,
38
+ });
39
+ }
40
+ const { data } = response;
41
+
42
+ throw getRichError(response.status, data ? data.message || response.statusText : response.statusText, data);
43
+ });
44
+ };
45
+
46
+ module.exports = {
47
+ rp,
48
+ };
package/lib/validate.js CHANGED
@@ -3,7 +3,7 @@ const logger = require('@mimik/sumologic-winston-logger');
3
3
  const DETAILS = ['full', 'type', 'count'];
4
4
  const TYPE = DETAILS[1];
5
5
  const RESPONSE = 'response';
6
- const DEFAULT_LOG_LEVEL = logger.LEVELS[5]; // silly
6
+ const DEFAULT_LOGLEVEL = logger.LEVELS[5]; // silly
7
7
  const DEFAULT_RETRIES = 2;
8
8
  const MIN_RETRIES = 0;
9
9
  const MAX_RETRIES = 15;
@@ -22,7 +22,7 @@ const defaultRetry = (...args) => {
22
22
  const unknownRetry = () => true;
23
23
  const defaultDelay = () => DEFAULT_DELAY;
24
24
 
25
- const validateOptions = (options) => {
25
+ const validateOptions = (options, correlationId) => {
26
26
  if (!options.retry) {
27
27
  return {
28
28
  delay: DEFAULT_DELAY,
@@ -44,22 +44,22 @@ const validateOptions = (options) => {
44
44
  const validateLogLevel = (val, name) => {
45
45
  if (!val[name]) return null;
46
46
  if (!logger.LEVELS.includes(val[name])) {
47
- logger.warn(`invalid logLevel.${name}, reset to default`, { name, value: val[name], default: DEFAULT_LOG_LEVEL });
48
- return DEFAULT_LOG_LEVEL;
47
+ logger.warn(`invalid logLevel.${name}, reset to default`, { name, value: val[name], default: DEFAULT_LOGLEVEL }, correlationId);
48
+ return DEFAULT_LOGLEVEL;
49
49
  }
50
50
  return val[name];
51
51
  };
52
52
  const validateValue = (val, name, defaultValue, minValue, maxValue) => {
53
53
  if (typeof val !== 'number') {
54
- if (val) logger.warn(`invalid ${name}, reset to default`, { type: typeof val, defaultValue });
54
+ if (val) logger.warn(`invalid ${name}, reset to default`, { type: typeof val, defaultValue }, correlationId);
55
55
  return defaultValue;
56
56
  }
57
57
  if (val < minValue) {
58
- logger.warn(`out of scope ${name}, reset to min`, { value: val, minValue });
58
+ logger.warn(`out of scope ${name}, reset to min`, { value: val, minValue }, correlationId);
59
59
  return minValue;
60
60
  }
61
61
  if (val > maxValue) {
62
- logger.warn(`out of scope ${name}, reset to max`, { value: val, maxValue });
62
+ logger.warn(`out of scope ${name}, reset to max`, { value: val, maxValue }, correlationId);
63
63
  return maxValue;
64
64
  }
65
65
  return val;
@@ -67,7 +67,7 @@ const validateOptions = (options) => {
67
67
  const validateResponseDetails = (val, name, defaultValue) => {
68
68
  if (!val) return defaultValue;
69
69
  if (!DETAILS.includes(val)) {
70
- logger.warn(`invalid logLevel.${name}, reset to default`, { name, value: val, defaultValue });
70
+ logger.warn(`invalid logLevel.${name}, reset to default`, { name, value: val, defaultValue }, correlationId);
71
71
  return defaultValue;
72
72
  }
73
73
  return val;
@@ -75,7 +75,7 @@ const validateOptions = (options) => {
75
75
  const validateResponseName = (val, name, defaultValue) => {
76
76
  if (!val && val !== '') return defaultValue;
77
77
  if (typeof val !== 'string' || val.length === 0 || val.trim().length === 0) {
78
- logger.warn(`invalid logLevel.${name}, reset to default`, { name, value: val, defaultValue });
78
+ logger.warn(`invalid logLevel.${name}, reset to default`, { name, value: val, defaultValue }, correlationId);
79
79
  return defaultValue;
80
80
  }
81
81
  return val;
@@ -88,14 +88,14 @@ const validateOptions = (options) => {
88
88
  if (typeof delayStrategy !== 'function') {
89
89
  if (!delayStrategy) delayStrategy = defaultDelay;
90
90
  else {
91
- logger.warn('invalid delayStrategy, using delay', { strategyType: typeof delayStrategy, delay, default: DEFAULT_DELAY });
91
+ logger.warn('invalid delayStrategy, using delay', { strategyType: typeof delayStrategy, delay, default: DEFAULT_DELAY }, correlationId);
92
92
  delayStrategy = setDelay;
93
93
  }
94
94
  }
95
95
  if (typeof retryStrategy !== 'function') {
96
96
  if (!retryStrategy) retryStrategy = defaultRetry;
97
97
  else {
98
- logger.warn('invalid retryStrategy, ignoring', { strategyType: typeof retryStrategy, using: unknownRetry });
98
+ logger.warn('invalid retryStrategy, ignoring', { strategyType: typeof retryStrategy, using: unknownRetry }, correlationId);
99
99
  retryStrategy = unknownRetry;
100
100
  }
101
101
  }
@@ -0,0 +1,16 @@
1
+ /* eslint-disable no-console */
2
+ const express = require('express');
3
+ const bodyParser = require('body-parser');
4
+
5
+ const app = express();
6
+
7
+ app.use(bodyParser.json());
8
+ app.get(`/success`, (req, res) => {
9
+ res.statusCode = 200;
10
+
11
+ res.send({ statusCode: 200});
12
+ });
13
+
14
+ app.listen(9000, () => {
15
+ console.log('----->', `retry mock at ${9000}`);
16
+ });
@@ -0,0 +1,22 @@
1
+ require('../test/testEnv');
2
+
3
+ const { rpRetry } = require('../index');
4
+
5
+ const correlationId = `--request-retry-test--/${new Date().toISOString()}`;
6
+
7
+ const options = {
8
+ method: 'GET',
9
+ headers: {
10
+ 'x-correlation-id': correlationId,
11
+ },
12
+ url: 'http://localhost:9080/test/retry',
13
+ json: true,
14
+ retry: {},
15
+ };
16
+
17
+ options.retry.delayStrategy = () => 10000;
18
+ options.retry.timeout = 10;
19
+ options.retry.retries = 2;
20
+
21
+ rpRetry(options)
22
+ .catch((err) => console.log(err));
@@ -0,0 +1,60 @@
1
+ /* eslint-disable no-console */
2
+ const express = require('express');
3
+ const bodyParser = require('body-parser');
4
+
5
+ const app = express();
6
+ const config = {
7
+ port: 9080,
8
+ path: '/retry',
9
+ base: '/test',
10
+ get: {
11
+ nbRetry: 400,
12
+ success: 200,
13
+ error: 500,
14
+ },
15
+ post: {
16
+ success: 201,
17
+ },
18
+ };
19
+ let nbRequest = 0;
20
+ let time = 0;
21
+ let message;
22
+
23
+ app.use(bodyParser.json());
24
+ app.get(`${config.base}${config.path}`, (req, res) => {
25
+ if (nbRequest === 0) message = 'Recieved first request';
26
+ else {
27
+ const timeLap = Date.now() - time;
28
+
29
+ message = `Received ${nbRequest} retry with timelap ${timeLap}`;
30
+ }
31
+ console.log('----->', message);
32
+ time = Date.now();
33
+
34
+ if (nbRequest === config.get.nbRetry) {
35
+ res.statusCode = config.get.success;
36
+ res.send({ statusCode: config.get.success });
37
+ return;
38
+ }
39
+ nbRequest += 1;
40
+ res.statusCode = config.get.error;
41
+
42
+ res.send({ statusCode: config.get.error });
43
+ });
44
+ app.post(`${config.base}${config.path}`, (req, res) => {
45
+ console.log('----->', 'Received a POST request');
46
+ res.statusCode = config.post.success;
47
+ res.send({ statusCode: config.post.success });
48
+ });
49
+
50
+ app.post('/logs/:id', (req, res) => {
51
+ console.log('--->', 'Recieved a log');
52
+ console.log('---> id:', req.params.id)
53
+ console.log('---> body:', req.body);
54
+ res.statusCode = config.post.success;
55
+ res.send({ statusCode: config.post.success });
56
+ })
57
+
58
+ app.listen(config.port, () => {
59
+ console.log('----->', `retry mock at ${config.port}`);
60
+ });
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@mimik/request-retry",
3
- "version": "1.0.1",
4
- "description": "Request retry wrapping request-promise",
3
+ "version": "2.0.6",
4
+ "description": "Request retry wrapping axios",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "lint": "gulp lint",
8
8
  "docs": "gulp docs",
9
9
  "test": "nyc gulp test",
10
- "commit-ready": "gulp docs; gulp lint; npm run test"
10
+ "prepublishOnly": "gulp docs; gulp lint; npm run test",
11
+ "commit-ready": "gulp docs; gulp lint; npm run test",
12
+ "prepare": "husky install"
11
13
  },
12
14
  "husky": {
13
15
  "hooks": {
@@ -19,41 +21,44 @@
19
21
  "mimik",
20
22
  "microservice"
21
23
  ],
22
- "author": "mimik",
24
+ "author": "mimik technology inc <support@mimik.com> (https://developer.mimik.com/)",
23
25
  "license": "Apache-2.0",
24
26
  "repository": {
25
27
  "type": "git",
26
28
  "url": "https://bitbucket.org/mimiktech/request-retry"
27
29
  },
28
30
  "dependencies": {
29
- "@mimik/response-helper": "2.2.1",
30
- "@mimik/sumologic-winston-logger": "1.3.0",
31
- "bluebird": "3.7.1",
32
- "request": "2.88.0",
33
- "request-promise": "4.2.5"
31
+ "@mimik/request-helper": "^1.7.3",
32
+ "@mimik/response-helper": "^2.6.0",
33
+ "@mimik/sumologic-winston-logger": "^1.6.6",
34
+ "axios": "0.24.0",
35
+ "bluebird": "3.7.2",
36
+ "lodash": "4.17.21"
34
37
  },
35
38
  "devDependencies": {
36
- "acorn": "7.1.0",
37
- "body-parser": "1.19.0",
38
- "chai": "4.2.0",
39
- "eslint": "6.6.0",
40
- "eslint-config-airbnb": "18.0.1",
41
- "eslint-plugin-import": "2.18.2",
42
- "eslint-plugin-jsx-a11y": "6.2.3",
43
- "eslint-plugin-react": "7.16.0",
44
- "eslint-plugin-react-hooks": "2.2.0",
39
+ "@mimik/eslint-plugin-dependencies": "^2.4.1",
40
+ "@mimik/eslint-plugin-document-env": "^1.0.0",
41
+ "acorn": "8.6.0",
42
+ "body-parser": "1.19.1",
43
+ "chai": "4.3.4",
44
+ "eslint": "8.4.1",
45
+ "eslint-config-airbnb": "18.2.1",
46
+ "eslint-plugin-import": "2.25.3",
47
+ "eslint-plugin-jsx-a11y": "6.5.1",
48
+ "eslint-plugin-react": "7.27.1",
49
+ "eslint-plugin-react-hooks": "4.3.0",
45
50
  "express": "4.17.1",
46
51
  "fancy-log": "1.3.3",
47
52
  "gulp": "4.0.2",
48
53
  "gulp-eslint": "6.0.0",
49
- "gulp-git": "2.9.0",
54
+ "gulp-git": "2.10.1",
50
55
  "gulp-spawn-mocha": "6.0.0",
51
- "husky": "3.0.9",
52
- "jsdoc-to-markdown": "5.0.2",
53
- "mocha": "6.2.2",
54
- "mochawesome": "4.1.0",
55
- "nyc": "14.1.1",
56
- "sinon": "7.5.0",
57
- "verror": "1.10.0"
56
+ "husky": "7.0.4",
57
+ "jsdoc-to-markdown": "7.1.0",
58
+ "mocha": "9.1.3",
59
+ "mochawesome": "7.0.1",
60
+ "nyc": "15.1.0",
61
+ "sinon": "12.0.1",
62
+ "verror": "1.10.1"
58
63
  }
59
64
  }
@@ -2,10 +2,11 @@ const chai = require('chai');
2
2
  const sinon = require('sinon');
3
3
  const VError = require('verror');
4
4
  const { beforeEach, afterEach } = require('mocha');
5
+ require('./testEnv');
5
6
 
6
7
  const logger = require('@mimik/sumologic-winston-logger');
8
+ const { getCorrelationId } = require('@mimik/request-helper');
7
9
 
8
- require('./testEnv');
9
10
  const mockServer = require('./retryMock');
10
11
  const { rpRetry } = require('../index');
11
12
 
@@ -16,7 +17,7 @@ chai.should();
16
17
  // const NO_ERROR = 'not an error object';
17
18
 
18
19
  describe('request-retry Unit Tests', () => {
19
- const correlationId = '--request-retry-test--';
20
+ const correlationId = getCorrelationId('--request-retry-test--');
20
21
  // let loggerSpyError;
21
22
  let loggerSpyWarn;
22
23
  let loggerSpyInfo;
@@ -261,7 +262,7 @@ describe('request-retry Unit Tests', () => {
261
262
  options.retry.retries = 2;
262
263
  return rpRetry(options)
263
264
  .catch(() => {
264
- sinon.assert.calledTwice(loggerSpyWarn);
265
+ sinon.assert.called(loggerSpyWarn);
265
266
  const callArgs = loggerSpyWarn.getCall(0).args;
266
267
  expect(callArgs[0]).to.be.a('string');
267
268
  expect(callArgs[0]).to.equal('bad retry strategy');
@@ -272,7 +273,7 @@ describe('request-retry Unit Tests', () => {
272
273
  options.retry.retries = 2;
273
274
  return rpRetry(options)
274
275
  .catch(() => {
275
- sinon.assert.calledTwice(loggerSpyWarn);
276
+ sinon.assert.called(loggerSpyWarn);
276
277
  const callArgs = loggerSpyWarn.getCall(0).args;
277
278
  expect(callArgs[0]).to.be.a('string');
278
279
  expect(callArgs[0]).to.equal('bad retry strategy');
@@ -282,10 +283,8 @@ describe('request-retry Unit Tests', () => {
282
283
  options.retry.retryStrategy = () => false;
283
284
  options.retry.retries = 2;
284
285
  return rpRetry(options)
285
- .then(() => {
286
- })
287
286
  .catch(() => {
288
- sinon.assert.notCalled(loggerSpyWarn);
287
+ sinon.assert.called(loggerSpyWarn);
289
288
  });
290
289
  });
291
290
  it('should generate warning: bad delay strategy (throwing an error), ignoring and using default delay', () => {
@@ -293,7 +292,7 @@ describe('request-retry Unit Tests', () => {
293
292
  options.retry.retries = 2;
294
293
  return rpRetry(options)
295
294
  .catch(() => {
296
- sinon.assert.calledTwice(loggerSpyWarn);
295
+ sinon.assert.called(loggerSpyWarn);
297
296
  const callArgs = loggerSpyWarn.getCall(0).args;
298
297
  expect(callArgs[0]).to.be.a('string');
299
298
  expect(callArgs[0]).to.equal('bad delay strategy');
@@ -304,7 +303,7 @@ describe('request-retry Unit Tests', () => {
304
303
  options.retry.retries = 2;
305
304
  return rpRetry(options)
306
305
  .catch(() => {
307
- sinon.assert.calledTwice(loggerSpyWarn);
306
+ sinon.assert.called(loggerSpyWarn);
308
307
  const callArgs = loggerSpyWarn.getCall(0).args;
309
308
  expect(callArgs[0]).to.be.a('string');
310
309
  expect(callArgs[0]).to.equal('bad delay strategy');
@@ -315,7 +314,7 @@ describe('request-retry Unit Tests', () => {
315
314
  options.retry.retries = 2;
316
315
  return rpRetry(options)
317
316
  .catch(() => {
318
- sinon.assert.calledTwice(loggerSpyWarn);
317
+ sinon.assert.called(loggerSpyWarn);
319
318
  const callArgs = loggerSpyWarn.getCall(0).args;
320
319
  expect(callArgs[0]).to.be.a('string');
321
320
  expect(callArgs[0]).to.equal('calculated delay out of scope: using delay or default');
@@ -325,10 +324,8 @@ describe('request-retry Unit Tests', () => {
325
324
  options.retry.delayStrategy = () => 50;
326
325
  options.retry.retries = 2;
327
326
  return rpRetry(options)
328
- .then(() => {
329
- })
330
327
  .catch(() => {
331
- sinon.assert.notCalled(loggerSpyWarn);
328
+ sinon.assert.called(loggerSpyWarn);
332
329
  });
333
330
  });
334
331
  it('should generate a timeout error', () => {
@@ -336,12 +333,10 @@ describe('request-retry Unit Tests', () => {
336
333
  options.retry.timeout = 10;
337
334
  options.retry.retries = 2;
338
335
  return rpRetry(options)
339
- .then(() => {
340
- })
341
336
  .catch((err) => {
342
337
  expect(err.name).to.equal('System');
343
338
  expect(VError.cause(err).name).to.equal('TimeoutError');
344
- sinon.assert.notCalled(loggerSpyWarn);
339
+ // sinon.assert.called(loggerSpyWarn);
345
340
  });
346
341
  });
347
342
  });
package/test/testEnv.js CHANGED
@@ -1,5 +1,21 @@
1
+ /* eslint no-process-env: "off" */
2
+
3
+ /**
4
+ * The following environment variables are set for the test:
5
+ *
6
+ * | Env variable name | Description | Default | Comments |
7
+ * | ----------------- | ----------- | ------- | -------- |
8
+ * | SUMO_LOGIC_ENDPOINT | endpoint to use to log on sumologic | null
9
+ * | SUMO_LOGIC_COLLECTOR_CODE | code to use to log on sumologic | null
10
+ * | NO_STACK | flag to have a stack associated with the log | yes
11
+ * | LOG_LEVEL | log level to log | error
12
+ * | CONSOLE_LEVEL | log level to diplay | debug
13
+ */
14
+
15
+ // process.env.SUMO_LOGIC_ENDPOINT = 'http://localhost:9080/logs/';
16
+ // process.env.SUMO_LOGIC_COLLECTOR_CODE = '1234';
1
17
  process.env.SUMO_LOGIC_ENDPOINT = null;
2
18
  process.env.SUMO_LOGIC_COLLECTOR_CODE = null;
3
19
  process.env.NO_STACK = 'yes';
4
- process.env.LOG_LEVEL = 'error';
5
- // process.env.CONSOLE_LEVEL = 'debug';
20
+ process.env.LOG_LEVEL = 'debug';
21
+ process.env.CONSOLE_LEVEL = 'debug';
package/package.json.bak DELETED
@@ -1,60 +0,0 @@
1
- {
2
- "name": "@mimik/request-retry",
3
- "version": "1.0.1",
4
- "description": "Request retry wrapping request-promise",
5
- "main": "index.js",
6
- "scripts": {
7
- "lint": "gulp lint",
8
- "docs": "gulp docs",
9
- "test": "nyc gulp test",
10
- "prepublishOnly": "gulp docs; gulp lint; npm run test",
11
- "commit-ready": "gulp docs; gulp lint; npm run test"
12
- },
13
- "husky": {
14
- "hooks": {
15
- "pre-commit": "npm run commit-ready",
16
- "pre-push": "npm run test"
17
- }
18
- },
19
- "keywords": [
20
- "mimik",
21
- "microservice"
22
- ],
23
- "author": "mimik",
24
- "license": "Apache-2.0",
25
- "repository": {
26
- "type": "git",
27
- "url": "https://bitbucket.org/mimiktech/request-retry"
28
- },
29
- "dependencies": {
30
- "@mimik/response-helper": "2.2.1",
31
- "@mimik/sumologic-winston-logger": "1.3.0",
32
- "bluebird": "3.7.1",
33
- "request": "2.88.0",
34
- "request-promise": "4.2.5"
35
- },
36
- "devDependencies": {
37
- "acorn": "7.1.0",
38
- "body-parser": "1.19.0",
39
- "chai": "4.2.0",
40
- "eslint": "6.6.0",
41
- "eslint-config-airbnb": "18.0.1",
42
- "eslint-plugin-import": "2.18.2",
43
- "eslint-plugin-jsx-a11y": "6.2.3",
44
- "eslint-plugin-react": "7.16.0",
45
- "eslint-plugin-react-hooks": "2.2.0",
46
- "express": "4.17.1",
47
- "fancy-log": "1.3.3",
48
- "gulp": "4.0.2",
49
- "gulp-eslint": "6.0.0",
50
- "gulp-git": "2.9.0",
51
- "gulp-spawn-mocha": "6.0.0",
52
- "husky": "3.0.9",
53
- "jsdoc-to-markdown": "5.0.2",
54
- "mocha": "6.2.2",
55
- "mochawesome": "4.1.0",
56
- "nyc": "14.1.1",
57
- "sinon": "7.5.0",
58
- "verror": "1.10.0"
59
- }
60
- }