From 8c134282bb471e2e2593710d4a147fb63f28648a Mon Sep 17 00:00:00 2001 From: Sachin Iyer Date: Thu, 16 Oct 2025 21:43:56 -0700 Subject: [PATCH 1/5] fix: timeoutSignal is lost after being overriden with controller.signal --- src/watch.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/watch.ts b/src/watch.ts index 4c51399a62..d977a71762 100644 --- a/src/watch.ts +++ b/src/watch.ts @@ -41,7 +41,6 @@ export class Watch { const controller = new AbortController(); const timeoutSignal = AbortSignal.timeout(30000); requestInit.signal = AbortSignal.any([controller.signal, timeoutSignal]); - requestInit.signal = controller.signal as AbortSignal; requestInit.method = 'GET'; let doneCalled: boolean = false; From d02aeaf63e33d5353aa74ea16925adb3ee45e9b7 Mon Sep 17 00:00:00 2001 From: Sachin Iyer Date: Thu, 16 Oct 2025 21:43:56 -0700 Subject: [PATCH 2/5] fix: timeoutSignal is lost after being overriden with controller.signal --- src/watch.ts | 3 ++- src/watch_test.ts | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/watch.ts b/src/watch.ts index d977a71762..c8bcd3e337 100644 --- a/src/watch.ts +++ b/src/watch.ts @@ -6,6 +6,7 @@ import { KubeConfig } from './config.js'; export class Watch { public static SERVER_SIDE_CLOSE: object = { error: 'Connection closed on server' }; public config: KubeConfig; + private defaultRequestTimeoutMs: number = 30000; public constructor(config: KubeConfig) { this.config = config; @@ -39,7 +40,7 @@ export class Watch { const requestInit = await this.config.applyToFetchOptions({}); const controller = new AbortController(); - const timeoutSignal = AbortSignal.timeout(30000); + const timeoutSignal = AbortSignal.timeout(this.defaultRequestTimeoutMs); requestInit.signal = AbortSignal.any([controller.signal, timeoutSignal]); requestInit.method = 'GET'; diff --git a/src/watch_test.ts b/src/watch_test.ts index 5bf842565d..2251f3232e 100644 --- a/src/watch_test.ts +++ b/src/watch_test.ts @@ -452,6 +452,41 @@ describe('Watch', () => { s.done(); }); + it('should timeout when server takes too long to respond', async (t) => { + const kc = await setupMockSystem(t, (_req: any, _res: any) => { + // Don't respond - simulate a hanging server + }); + const watch = new Watch(kc); + // Hack around type system to make the default timeout shorter. + (watch as any).timeoutMs = 100; + + let doneCalled = false; + let doneErr: any; + + let doneResolve: () => void; + const donePromise = new Promise((resolve) => { + doneResolve = resolve; + }); + + await watch.watch( + '/some/path/to/object', + {}, + () => { + throw new Error('Unexpected data received - timeout should have occurred before any data'); + }, + (err: any) => { + doneCalled = true; + doneErr = err; + doneResolve(); + }, + ); + + await donePromise; + + strictEqual(doneCalled, true); + strictEqual(doneErr.name, 'AbortError'); + }); + it('should throw on empty config', async () => { const kc = new KubeConfig(); const watch = new Watch(kc); From 3cf72af67b997712735174d1634f85b0c6c9254c Mon Sep 17 00:00:00 2001 From: Sachin Iyer Date: Thu, 16 Oct 2025 21:43:56 -0700 Subject: [PATCH 3/5] fix: timeoutSignal is lost after being overriden with controller.signal --- src/watch.ts | 4 ++-- src/watch_test.ts | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/watch.ts b/src/watch.ts index c8bcd3e337..7664b07291 100644 --- a/src/watch.ts +++ b/src/watch.ts @@ -6,7 +6,7 @@ import { KubeConfig } from './config.js'; export class Watch { public static SERVER_SIDE_CLOSE: object = { error: 'Connection closed on server' }; public config: KubeConfig; - private defaultRequestTimeoutMs: number = 30000; + private requestTimeoutMs: number = 30000; public constructor(config: KubeConfig) { this.config = config; @@ -40,7 +40,7 @@ export class Watch { const requestInit = await this.config.applyToFetchOptions({}); const controller = new AbortController(); - const timeoutSignal = AbortSignal.timeout(this.defaultRequestTimeoutMs); + const timeoutSignal = AbortSignal.timeout(this.requestTimeoutMs); requestInit.signal = AbortSignal.any([controller.signal, timeoutSignal]); requestInit.method = 'GET'; diff --git a/src/watch_test.ts b/src/watch_test.ts index 2251f3232e..97a318a12c 100644 --- a/src/watch_test.ts +++ b/src/watch_test.ts @@ -457,8 +457,9 @@ describe('Watch', () => { // Don't respond - simulate a hanging server }); const watch = new Watch(kc); - // Hack around type system to make the default timeout shorter. - (watch as any).timeoutMs = 100; + + // NOTE: Hack around the type system to make the timeout shorter + (watch as any).requestTimeoutMs = 100; let doneCalled = false; let doneErr: any; From 3701edd396fe89acdba6c69341f32bf317748610 Mon Sep 17 00:00:00 2001 From: Sachin Iyer Date: Thu, 16 Oct 2025 21:43:56 -0700 Subject: [PATCH 4/5] fix: timeoutSignal is lost after being overriden with controller.signal --- src/watch_test.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/watch_test.ts b/src/watch_test.ts index 97a318a12c..d690bb8c1a 100644 --- a/src/watch_test.ts +++ b/src/watch_test.ts @@ -459,9 +459,8 @@ describe('Watch', () => { const watch = new Watch(kc); // NOTE: Hack around the type system to make the timeout shorter - (watch as any).requestTimeoutMs = 100; + (watch as any).requestTimeoutMs = 1; - let doneCalled = false; let doneErr: any; let doneResolve: () => void; @@ -476,7 +475,6 @@ describe('Watch', () => { throw new Error('Unexpected data received - timeout should have occurred before any data'); }, (err: any) => { - doneCalled = true; doneErr = err; doneResolve(); }, @@ -484,7 +482,6 @@ describe('Watch', () => { await donePromise; - strictEqual(doneCalled, true); strictEqual(doneErr.name, 'AbortError'); }); From b3d7800959f1621239a5fc96a4a9f0a7250e1d26 Mon Sep 17 00:00:00 2001 From: Sachin Iyer Date: Thu, 16 Oct 2025 21:43:56 -0700 Subject: [PATCH 5/5] fix: timeoutSignal is lost after being overriden with controller.signal --- src/watch_test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/watch_test.ts b/src/watch_test.ts index d690bb8c1a..7be5c1f6c0 100644 --- a/src/watch_test.ts +++ b/src/watch_test.ts @@ -459,7 +459,7 @@ describe('Watch', () => { const watch = new Watch(kc); // NOTE: Hack around the type system to make the timeout shorter - (watch as any).requestTimeoutMs = 1; + (watch as any).requestTimeoutMs = 10; let doneErr: any;