@spoosh/plugin-retry 0.1.9 → 0.3.0

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/README.md CHANGED
@@ -16,7 +16,7 @@ npm install @spoosh/plugin-retry
16
16
  import { Spoosh } from "@spoosh/core";
17
17
  import { retryPlugin } from "@spoosh/plugin-retry";
18
18
 
19
- const client = new Spoosh<ApiSchema, Error>("/api").use([
19
+ const spoosh = new Spoosh<ApiSchema, Error>("/api").use([
20
20
  retryPlugin({ retries: 3, retryDelay: 1000 }),
21
21
  ]);
22
22
 
package/dist/index.d.mts CHANGED
@@ -35,7 +35,7 @@ type RetryWriteResult = object;
35
35
  * ```ts
36
36
  * import { Spoosh } from "@spoosh/core";
37
37
  *
38
- * const client = new Spoosh<ApiSchema, Error>("/api")
38
+ * const spoosh = new Spoosh<ApiSchema, Error>("/api")
39
39
  * .use([
40
40
  * // ... other plugins
41
41
  * retryPlugin({ retries: 3, retryDelay: 1000 }),
package/dist/index.d.ts CHANGED
@@ -35,7 +35,7 @@ type RetryWriteResult = object;
35
35
  * ```ts
36
36
  * import { Spoosh } from "@spoosh/core";
37
37
  *
38
- * const client = new Spoosh<ApiSchema, Error>("/api")
38
+ * const spoosh = new Spoosh<ApiSchema, Error>("/api")
39
39
  * .use([
40
40
  * // ... other plugins
41
41
  * retryPlugin({ retries: 3, retryDelay: 1000 }),
package/dist/index.js CHANGED
@@ -25,21 +25,60 @@ __export(src_exports, {
25
25
  module.exports = __toCommonJS(src_exports);
26
26
 
27
27
  // src/plugin.ts
28
+ var import_core = require("@spoosh/core");
29
+ var PLUGIN_NAME = "spoosh:retry";
30
+ var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
28
31
  function retryPlugin(config = {}) {
29
32
  const { retries: defaultRetries = 3, retryDelay: defaultRetryDelay = 1e3 } = config;
30
33
  return {
31
- name: "spoosh:retry",
34
+ name: PLUGIN_NAME,
32
35
  operations: ["read", "write", "infiniteRead"],
36
+ priority: 200,
33
37
  middleware: async (context, next) => {
38
+ const t = context.tracer?.(PLUGIN_NAME);
34
39
  const pluginOptions = context.pluginOptions;
35
- const retries = pluginOptions?.retries ?? defaultRetries;
36
- const retryDelay = pluginOptions?.retryDelay ?? defaultRetryDelay;
37
- context.request = {
38
- ...context.request,
39
- retries,
40
- retryDelay
40
+ const retriesConfig = pluginOptions?.retries ?? defaultRetries;
41
+ const retryDelayConfig = pluginOptions?.retryDelay ?? defaultRetryDelay;
42
+ const maxRetries = retriesConfig === false ? 0 : retriesConfig;
43
+ if (!maxRetries || maxRetries < 0) {
44
+ t?.skip("Disabled");
45
+ return next();
46
+ }
47
+ const originalRequest = {
48
+ headers: (0, import_core.clone)(context.request.headers),
49
+ params: (0, import_core.clone)(context.request.params),
50
+ body: (0, import_core.clone)(context.request.body)
41
51
  };
42
- return next();
52
+ let res;
53
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
54
+ if (attempt > 0) {
55
+ context.request.headers = (0, import_core.clone)(originalRequest.headers);
56
+ context.request.params = (0, import_core.clone)(originalRequest.params);
57
+ context.request.body = (0, import_core.clone)(originalRequest.body);
58
+ t?.log(`Retry ${attempt}/${maxRetries}`, { color: "warning" });
59
+ }
60
+ res = await next();
61
+ if ((0, import_core.isAbortError)(res.error)) {
62
+ t?.log("Aborted", { color: "muted" });
63
+ return res;
64
+ }
65
+ if ((0, import_core.isNetworkError)(res.error) && attempt < maxRetries) {
66
+ const delayMs = retryDelayConfig * Math.pow(2, attempt);
67
+ await delay(delayMs);
68
+ continue;
69
+ }
70
+ if (attempt > 0) {
71
+ if ((0, import_core.isNetworkError)(res.error)) {
72
+ t?.log("Max retries reached or non-retryable error", {
73
+ color: "error"
74
+ });
75
+ } else {
76
+ t?.log("Retry succeeded", { color: "success" });
77
+ }
78
+ }
79
+ return res;
80
+ }
81
+ return res;
43
82
  }
44
83
  };
45
84
  }
package/dist/index.mjs CHANGED
@@ -1,19 +1,58 @@
1
1
  // src/plugin.ts
2
+ import { isNetworkError, isAbortError, clone } from "@spoosh/core";
3
+ var PLUGIN_NAME = "spoosh:retry";
4
+ var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
2
5
  function retryPlugin(config = {}) {
3
6
  const { retries: defaultRetries = 3, retryDelay: defaultRetryDelay = 1e3 } = config;
4
7
  return {
5
- name: "spoosh:retry",
8
+ name: PLUGIN_NAME,
6
9
  operations: ["read", "write", "infiniteRead"],
10
+ priority: 200,
7
11
  middleware: async (context, next) => {
12
+ const t = context.tracer?.(PLUGIN_NAME);
8
13
  const pluginOptions = context.pluginOptions;
9
- const retries = pluginOptions?.retries ?? defaultRetries;
10
- const retryDelay = pluginOptions?.retryDelay ?? defaultRetryDelay;
11
- context.request = {
12
- ...context.request,
13
- retries,
14
- retryDelay
14
+ const retriesConfig = pluginOptions?.retries ?? defaultRetries;
15
+ const retryDelayConfig = pluginOptions?.retryDelay ?? defaultRetryDelay;
16
+ const maxRetries = retriesConfig === false ? 0 : retriesConfig;
17
+ if (!maxRetries || maxRetries < 0) {
18
+ t?.skip("Disabled");
19
+ return next();
20
+ }
21
+ const originalRequest = {
22
+ headers: clone(context.request.headers),
23
+ params: clone(context.request.params),
24
+ body: clone(context.request.body)
15
25
  };
16
- return next();
26
+ let res;
27
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
28
+ if (attempt > 0) {
29
+ context.request.headers = clone(originalRequest.headers);
30
+ context.request.params = clone(originalRequest.params);
31
+ context.request.body = clone(originalRequest.body);
32
+ t?.log(`Retry ${attempt}/${maxRetries}`, { color: "warning" });
33
+ }
34
+ res = await next();
35
+ if (isAbortError(res.error)) {
36
+ t?.log("Aborted", { color: "muted" });
37
+ return res;
38
+ }
39
+ if (isNetworkError(res.error) && attempt < maxRetries) {
40
+ const delayMs = retryDelayConfig * Math.pow(2, attempt);
41
+ await delay(delayMs);
42
+ continue;
43
+ }
44
+ if (attempt > 0) {
45
+ if (isNetworkError(res.error)) {
46
+ t?.log("Max retries reached or non-retryable error", {
47
+ color: "error"
48
+ });
49
+ } else {
50
+ t?.log("Retry succeeded", { color: "success" });
51
+ }
52
+ }
53
+ return res;
54
+ }
55
+ return res;
17
56
  }
18
57
  };
19
58
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spoosh/plugin-retry",
3
- "version": "0.1.9",
3
+ "version": "0.3.0",
4
4
  "description": "Automatic retry plugin for Spoosh with configurable attempts and delay",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -33,11 +33,11 @@
33
33
  }
34
34
  },
35
35
  "peerDependencies": {
36
- "@spoosh/core": ">=0.12.0"
36
+ "@spoosh/core": ">=0.13.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@spoosh/core": "0.12.0",
40
- "@spoosh/test-utils": "0.1.8"
39
+ "@spoosh/test-utils": "0.2.0",
40
+ "@spoosh/core": "0.13.0"
41
41
  },
42
42
  "scripts": {
43
43
  "dev": "tsup --watch",