kubernetes-fluent-client 3.10.12 → 3.10.13
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/dist/fluent/watch.d.ts.map +1 -1
- package/dist/fluent/watch.js +25 -7
- package/package.json +7 -7
- package/src/fluent/watch.ts +40 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/fluent/watch.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/fluent/watch.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,YAAY,EAAwB,MAAM,aAAa,CAAC;AAGjE,OAAO,EAGL,WAAW,EACX,OAAO,EAER,MAAM,mBAAmB,CAAC;AAK3B,oBAAY,UAAU;IACpB,sCAAsC;IACtC,OAAO,YAAY;IACnB,2BAA2B;IAC3B,aAAa,kBAAkB;IAC/B,kDAAkD;IAClD,UAAU,eAAe;IACzB,0BAA0B;IAC1B,SAAS,cAAc;IACvB,8BAA8B;IAC9B,OAAO,YAAY;IACnB,sBAAsB;IACtB,KAAK,UAAU;IACf,mCAAmC;IACnC,IAAI,SAAS;IACb,wCAAwC;IACxC,oBAAoB,yBAAyB;IAC7C,qCAAqC;IACrC,iBAAiB,sBAAsB;IACvC,kCAAkC;IAClC,IAAI,SAAS;IACb,2BAA2B;IAC3B,UAAU,eAAe;IACzB,mBAAmB;IACnB,UAAU,eAAe;IACzB,qCAAqC;IACrC,wBAAwB,6BAA6B;IACrD,iCAAiC;IACjC,eAAe,oBAAoB;CACpC;AAED,4CAA4C;AAC5C,MAAM,MAAM,QAAQ,GAAG;IACrB,+HAA+H;IAC/H,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+FAA+F;IAC/F,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,wHAAwH;IACxH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAKF,iDAAiD;AACjD,qBAAa,OAAO,CAAC,CAAC,SAAS,YAAY;;IAyBzC,YAAY,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;IAc9B;;;;;;;;;;;OAWG;gBACS,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,GAAE,QAAa;IA0CzF;;;;OAIG;IACU,KAAK,IAAI,OAAO,CAAC,eAAe,CAAC;IAO9C,gGAAgG;IACzF,KAAK;IAQZ;;;;;;OAMG;IACH,IAAW,MAAM,IAAI,YAAY,CAEhC;CAwXF"}
|
package/dist/fluent/watch.js
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
// SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
|
|
3
3
|
import { EventEmitter } from "events";
|
|
4
4
|
import { fetch } from "undici";
|
|
5
|
-
import { fetch as wrappedFetch } from "../fetch.js";
|
|
6
5
|
import { k8sCfg, pathBuilder, getHeaders } from "./utils.js";
|
|
7
6
|
import { Readable } from "stream";
|
|
8
7
|
import { WatchPhase, FetchMethods, } from "./shared-types.js";
|
|
8
|
+
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
9
|
+
const startSleep = 5000;
|
|
9
10
|
export var WatchEvent;
|
|
10
11
|
(function (WatchEvent) {
|
|
11
12
|
/** Watch is connected successfully */
|
|
@@ -174,16 +175,28 @@ export class Watcher {
|
|
|
174
175
|
*
|
|
175
176
|
* @param continueToken - the continue token for the list
|
|
176
177
|
* @param removedItems - the list of items that have been removed
|
|
178
|
+
* @param retryCount - current retry attempt count
|
|
177
179
|
*/
|
|
178
|
-
#list = async (continueToken, removedItems) => {
|
|
180
|
+
#list = async (continueToken, removedItems, retryCount = 0) => {
|
|
181
|
+
const maxRetries = 5;
|
|
182
|
+
const maxPages = 10;
|
|
179
183
|
try {
|
|
180
184
|
const { opts, serverUrl } = await this.#buildURL(false, undefined, continueToken);
|
|
181
185
|
// Make the request to list the resources
|
|
182
|
-
const response = await
|
|
183
|
-
const list = response.
|
|
186
|
+
const response = await fetch(serverUrl, opts);
|
|
187
|
+
const list = (await response.json());
|
|
184
188
|
// If the request fails, emit an error event and return
|
|
185
189
|
if (!response.ok) {
|
|
186
|
-
this.#events.emit(WatchEvent.LIST_ERROR, new Error(`list failed: ${response.status} ${response.statusText}`));
|
|
190
|
+
this.#events.emit(WatchEvent.LIST_ERROR, new Error(`list failed: ${response.status} ${response.statusText} ${JSON.stringify([...response.headers])}`));
|
|
191
|
+
// Retry with exponential backoff if under retry limit to prevent infinite recursion if the server is returning errors
|
|
192
|
+
if (retryCount < maxRetries) {
|
|
193
|
+
const retryAfterHeader = response.headers.get("retry-after");
|
|
194
|
+
const backoffTime = retryAfterHeader
|
|
195
|
+
? parseInt(retryAfterHeader) * 1000
|
|
196
|
+
: Math.min(startSleep * Math.pow(2, retryCount), 30000);
|
|
197
|
+
await sleep(backoffTime);
|
|
198
|
+
return this.#list(continueToken, removedItems, retryCount + 1);
|
|
199
|
+
}
|
|
187
200
|
return;
|
|
188
201
|
}
|
|
189
202
|
// Gross hack, thanks upstream library :<
|
|
@@ -220,8 +233,13 @@ export class Watcher {
|
|
|
220
233
|
}
|
|
221
234
|
// If there is a continue token, call the list function again with the same removed items
|
|
222
235
|
if (continueToken) {
|
|
223
|
-
//
|
|
224
|
-
|
|
236
|
+
// Safeguard against infinite pagination
|
|
237
|
+
if (retryCount >= maxPages) {
|
|
238
|
+
this.#events.emit(WatchEvent.LIST_ERROR, new Error(`Maximum pagination limit (${maxPages}) reached, stopping list operation`));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
// Continue pagination (not a retry, so reset retryCount to 0)
|
|
242
|
+
await this.#list(continueToken, removedItems, 0);
|
|
225
243
|
}
|
|
226
244
|
else {
|
|
227
245
|
// Otherwise, process the removed items
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kubernetes-fluent-client",
|
|
3
|
-
"version": "3.10.
|
|
3
|
+
"version": "3.10.13",
|
|
4
4
|
"description": "A @kubernetes/client-node fluent API wrapper that leverages K8s Server Side Apply.",
|
|
5
5
|
"bin": "./dist/cli.js",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -61,8 +61,8 @@
|
|
|
61
61
|
"yargs": "18.0.0"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@commitlint/cli": "20.3.
|
|
65
|
-
"@commitlint/config-conventional": "20.3.
|
|
64
|
+
"@commitlint/cli": "20.3.1",
|
|
65
|
+
"@commitlint/config-conventional": "20.3.1",
|
|
66
66
|
"@defenseunicorns/eslint-config": "^1.1.2",
|
|
67
67
|
"@eslint/eslintrc": "^3.1.0",
|
|
68
68
|
"@eslint/js": "^9.14.0",
|
|
@@ -72,15 +72,15 @@
|
|
|
72
72
|
"@types/urijs": "^1.19.25",
|
|
73
73
|
"@types/ws": "^8.18.1",
|
|
74
74
|
"@types/yargs": "17.0.35",
|
|
75
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
76
|
-
"@typescript-eslint/parser": "8.
|
|
75
|
+
"@typescript-eslint/eslint-plugin": "8.53.1",
|
|
76
|
+
"@typescript-eslint/parser": "8.53.1",
|
|
77
77
|
"@vitest/coverage-v8": "^4.0.1",
|
|
78
78
|
"command-line-args": "^6.0.1",
|
|
79
|
-
"eslint-plugin-jsdoc": "
|
|
79
|
+
"eslint-plugin-jsdoc": "62.2.0",
|
|
80
80
|
"globals": "^17.0.0",
|
|
81
81
|
"husky": "^9.1.6",
|
|
82
82
|
"lint-staged": "^16.0.0",
|
|
83
|
-
"prettier": "3.
|
|
83
|
+
"prettier": "3.8.0",
|
|
84
84
|
"semantic-release": "25.0.2",
|
|
85
85
|
"typescript": "5.9.3",
|
|
86
86
|
"vitest": "^4.0.1"
|
package/src/fluent/watch.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
|
|
4
4
|
import { EventEmitter } from "events";
|
|
5
5
|
import { fetch } from "undici";
|
|
6
|
-
import { fetch as wrappedFetch } from "../fetch.js";
|
|
7
6
|
import { GenericClass, KubernetesListObject } from "../types.js";
|
|
8
7
|
import { k8sCfg, pathBuilder, getHeaders } from "./utils.js";
|
|
9
8
|
import { Readable } from "stream";
|
|
@@ -14,6 +13,10 @@ import {
|
|
|
14
13
|
Filters,
|
|
15
14
|
FetchMethods,
|
|
16
15
|
} from "./shared-types.js";
|
|
16
|
+
|
|
17
|
+
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
|
18
|
+
const startSleep = 5000;
|
|
19
|
+
|
|
17
20
|
export enum WatchEvent {
|
|
18
21
|
/** Watch is connected successfully */
|
|
19
22
|
CONNECT = "connect",
|
|
@@ -235,22 +238,43 @@ export class Watcher<T extends GenericClass> {
|
|
|
235
238
|
*
|
|
236
239
|
* @param continueToken - the continue token for the list
|
|
237
240
|
* @param removedItems - the list of items that have been removed
|
|
241
|
+
* @param retryCount - current retry attempt count
|
|
238
242
|
*/
|
|
239
|
-
#list = async (
|
|
243
|
+
#list = async (
|
|
244
|
+
continueToken?: string,
|
|
245
|
+
removedItems?: Map<string, InstanceType<T>>,
|
|
246
|
+
retryCount = 0,
|
|
247
|
+
): Promise<void> => {
|
|
248
|
+
const maxRetries = 5;
|
|
249
|
+
const maxPages = 10;
|
|
250
|
+
|
|
240
251
|
try {
|
|
241
252
|
const { opts, serverUrl } = await this.#buildURL(false, undefined, continueToken);
|
|
242
253
|
|
|
243
254
|
// Make the request to list the resources
|
|
244
|
-
const response = await
|
|
245
|
-
const list = response.
|
|
255
|
+
const response = await fetch(serverUrl, opts);
|
|
256
|
+
const list = (await response.json()) as KubernetesListObject<InstanceType<T>>;
|
|
246
257
|
|
|
247
258
|
// If the request fails, emit an error event and return
|
|
248
259
|
if (!response.ok) {
|
|
249
260
|
this.#events.emit(
|
|
250
261
|
WatchEvent.LIST_ERROR,
|
|
251
|
-
new Error(
|
|
262
|
+
new Error(
|
|
263
|
+
`list failed: ${response.status} ${response.statusText} ${JSON.stringify([...response.headers])}`,
|
|
264
|
+
),
|
|
252
265
|
);
|
|
253
266
|
|
|
267
|
+
// Retry with exponential backoff if under retry limit to prevent infinite recursion if the server is returning errors
|
|
268
|
+
if (retryCount < maxRetries) {
|
|
269
|
+
const retryAfterHeader = response.headers.get("retry-after");
|
|
270
|
+
const backoffTime = retryAfterHeader
|
|
271
|
+
? parseInt(retryAfterHeader) * 1000
|
|
272
|
+
: Math.min(startSleep * Math.pow(2, retryCount), 30000);
|
|
273
|
+
|
|
274
|
+
await sleep(backoffTime);
|
|
275
|
+
return this.#list(continueToken, removedItems, retryCount + 1);
|
|
276
|
+
}
|
|
277
|
+
|
|
254
278
|
return;
|
|
255
279
|
}
|
|
256
280
|
|
|
@@ -297,8 +321,17 @@ export class Watcher<T extends GenericClass> {
|
|
|
297
321
|
|
|
298
322
|
// If there is a continue token, call the list function again with the same removed items
|
|
299
323
|
if (continueToken) {
|
|
300
|
-
//
|
|
301
|
-
|
|
324
|
+
// Safeguard against infinite pagination
|
|
325
|
+
if (retryCount >= maxPages) {
|
|
326
|
+
this.#events.emit(
|
|
327
|
+
WatchEvent.LIST_ERROR,
|
|
328
|
+
new Error(`Maximum pagination limit (${maxPages}) reached, stopping list operation`),
|
|
329
|
+
);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Continue pagination (not a retry, so reset retryCount to 0)
|
|
334
|
+
await this.#list(continueToken, removedItems, 0);
|
|
302
335
|
} else {
|
|
303
336
|
// Otherwise, process the removed items
|
|
304
337
|
for (const item of removedItems.values()) {
|