From 59a943db90c72f270a1e8f86debc03bed5c6409b Mon Sep 17 00:00:00 2001 From: slvrtrn <hypnoash@gmail.com> Date: Thu, 28 Dec 2023 14:34:20 +0100 Subject: [PATCH 1/2] Make keep_alive configurable in the Web version --- .../integration/web_connection.test.ts | 42 +++++++++++++++++++ packages/client-web/src/client.ts | 16 ++++++- .../src/connection/web_connection.ts | 10 ++++- 3 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 packages/client-web/__tests__/integration/web_connection.test.ts diff --git a/packages/client-web/__tests__/integration/web_connection.test.ts b/packages/client-web/__tests__/integration/web_connection.test.ts new file mode 100644 index 00000000..20aa5bd3 --- /dev/null +++ b/packages/client-web/__tests__/integration/web_connection.test.ts @@ -0,0 +1,42 @@ +import { createClient } from '../../src' +import type { WebClickHouseClient } from '../../src/client' + +describe('[Web] Connection', () => { + let fetchSpy: jasmine.Spy<typeof window.fetch> + beforeEach(() => { + fetchSpy = spyOn(window, 'fetch').and.returnValue( + Promise.resolve(stubResponse()) + ) + }) + + describe('KeepAlive setting', () => { + it('should be enabled by default', async () => { + const client = createClient() + const fetchParams = await pingAndGetRequestInit(client) + expect(fetchParams.keepalive).toBeTruthy() + }) + + it('should be possible to disable it', async () => { + const client = createClient({ keep_alive: { enabled: false } }) + const fetchParams = await pingAndGetRequestInit(client) + expect(fetchParams!.keepalive).toBeFalsy() + }) + + it('should be enabled with an explicit setting', async () => { + const client = createClient({ keep_alive: { enabled: true } }) + const fetchParams = await pingAndGetRequestInit(client) + expect(fetchParams.keepalive).toBeTruthy() + }) + + async function pingAndGetRequestInit(client: WebClickHouseClient) { + await client.ping() + expect(fetchSpy).toHaveBeenCalledTimes(1) + const [, fetchParams] = fetchSpy.calls.mostRecent().args + return fetchParams! + } + }) + + function stubResponse() { + return new Response() + } +}) diff --git a/packages/client-web/src/client.ts b/packages/client-web/src/client.ts index 49c5bb49..4f0f02ca 100644 --- a/packages/client-web/src/client.ts +++ b/packages/client-web/src/client.ts @@ -15,6 +15,14 @@ import { WebConnection } from './connection' import { ResultSet } from './result_set' import { WebValuesEncoder } from './utils' +export type WebClickHouseClientConfigOptions = + BaseClickHouseClientConfigOptions<ReadableStream> & { + keep_alive?: { + /** Enable or disable HTTP Keep-Alive mechanism. Default: true */ + enabled: boolean + } + } + export type WebClickHouseClient = Omit< ClickHouseClient<ReadableStream>, 'insert' | 'query' @@ -30,11 +38,15 @@ export type WebClickHouseClient = Omit< } export function createClient( - config?: BaseClickHouseClientConfigOptions<ReadableStream> + config?: WebClickHouseClientConfigOptions ): WebClickHouseClient { + const keep_alive = { + enabled: config?.keep_alive?.enabled ?? true, + } return new ClickHouseClient<ReadableStream>({ impl: { - make_connection: (params: ConnectionParams) => new WebConnection(params), + make_connection: (params: ConnectionParams) => + new WebConnection({ ...params, keep_alive }), make_result_set: ( stream: ReadableStream, format: DataFormat, diff --git a/packages/client-web/src/connection/web_connection.ts b/packages/client-web/src/connection/web_connection.ts index 847ec65b..710736a7 100644 --- a/packages/client-web/src/connection/web_connection.ts +++ b/packages/client-web/src/connection/web_connection.ts @@ -24,9 +24,15 @@ type WebInsertParams<T> = Omit< values: string } +export type WebConnectionParams = ConnectionParams & { + keep_alive: { + enabled: boolean + } +} + export class WebConnection implements Connection<ReadableStream> { private readonly defaultHeaders: Record<string, string> - constructor(private readonly params: ConnectionParams) { + constructor(private readonly params: WebConnectionParams) { this.defaultHeaders = { Authorization: `Basic ${btoa(`${params.username}:${params.password}`)}`, } @@ -175,7 +181,7 @@ export class WebConnection implements Connection<ReadableStream> { const response = await fetch(url, { body: values, headers, - keepalive: false, + keepalive: this.params.keep_alive.enabled, method: method ?? 'POST', signal: abortController.signal, }) From 95eca7485dbdaa2fa78e0db0766728f655da0ede Mon Sep 17 00:00:00 2001 From: slvrtrn <hypnoash@gmail.com> Date: Thu, 28 Dec 2023 14:39:06 +0100 Subject: [PATCH 2/2] Simplify the test --- .../integration/web_connection.test.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/client-web/__tests__/integration/web_connection.test.ts b/packages/client-web/__tests__/integration/web_connection.test.ts index 20aa5bd3..b71121bb 100644 --- a/packages/client-web/__tests__/integration/web_connection.test.ts +++ b/packages/client-web/__tests__/integration/web_connection.test.ts @@ -2,14 +2,14 @@ import { createClient } from '../../src' import type { WebClickHouseClient } from '../../src/client' describe('[Web] Connection', () => { - let fetchSpy: jasmine.Spy<typeof window.fetch> - beforeEach(() => { - fetchSpy = spyOn(window, 'fetch').and.returnValue( - Promise.resolve(stubResponse()) - ) - }) - describe('KeepAlive setting', () => { + let fetchSpy: jasmine.Spy<typeof window.fetch> + beforeEach(() => { + fetchSpy = spyOn(window, 'fetch').and.returnValue( + Promise.resolve(new Response()) + ) + }) + it('should be enabled by default', async () => { const client = createClient() const fetchParams = await pingAndGetRequestInit(client) @@ -35,8 +35,4 @@ describe('[Web] Connection', () => { return fetchParams! } }) - - function stubResponse() { - return new Response() - } })