diff --git a/src/watch.ts b/src/watch.ts index 4c51399a62..7664b07291 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 requestTimeoutMs: number = 30000; public constructor(config: KubeConfig) { this.config = config; @@ -39,9 +40,8 @@ export class Watch { const requestInit = await this.config.applyToFetchOptions({}); const controller = new AbortController(); - const timeoutSignal = AbortSignal.timeout(30000); + const timeoutSignal = AbortSignal.timeout(this.requestTimeoutMs); requestInit.signal = AbortSignal.any([controller.signal, timeoutSignal]); - requestInit.signal = controller.signal as AbortSignal; requestInit.method = 'GET'; let doneCalled: boolean = false; diff --git a/src/watch_test.ts b/src/watch_test.ts index 5bf842565d..d690bb8c1a 100644 --- a/src/watch_test.ts +++ b/src/watch_test.ts @@ -452,6 +452,39 @@ 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); + + // NOTE: Hack around the type system to make the timeout shorter + (watch as any).requestTimeoutMs = 1; + + 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) => { + doneErr = err; + doneResolve(); + }, + ); + + await donePromise; + + strictEqual(doneErr.name, 'AbortError'); + }); + it('should throw on empty config', async () => { const kc = new KubeConfig(); const watch = new Watch(kc);