From 529e7075a2c6533845b2af2a5e07ffd60060bc58 Mon Sep 17 00:00:00 2001 From: Josh Mock Date: Thu, 17 Apr 2025 10:45:18 -0500 Subject: [PATCH] Put node roles support back (#2759) (cherry picked from commit eeb0d9404681881009a286335ae28cd4216c727d) --- docs/basic-config.asciidoc | 13 ++++++++++++- src/client.ts | 9 ++++++++- test/unit/client.test.ts | 25 +++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/docs/basic-config.asciidoc b/docs/basic-config.asciidoc index a77a799ea..ffc1d3486 100644 --- a/docs/basic-config.asciidoc +++ b/docs/basic-config.asciidoc @@ -171,7 +171,18 @@ a|`function` - Takes a `Connection` and returns `true` if it can be sent a reque _Default:_ [source,js] ---- -() => true +function defaultNodeFilter (conn) { + if (conn.roles != null) { + if ( + // avoid master-only nodes + conn.roles.master && + !conn.roles.data && + !conn.roles.ingest && + !conn.roles.ml + ) return false + } + return true +} ---- |`nodeSelector` diff --git a/src/client.ts b/src/client.ts index ed40d1836..5ff5b061e 100644 --- a/src/client.ts +++ b/src/client.ts @@ -78,6 +78,13 @@ export interface NodeOptions { ssl?: TlsConnectionOptions /** @property headers Custom HTTP headers that should be sent with each request */ headers?: Record + /** @property roles Common Elasticsearch roles that can be assigned to this node. Can be helpful when writing custom nodeFilter or nodeSelector functions. */ + roles?: { + master: boolean + data: boolean + ingest: boolean + ml: boolean + } } export interface ClientOptions { @@ -135,7 +142,7 @@ export interface ClientOptions { * @defaultValue null */ agent?: HttpAgentOptions | UndiciAgentOptions | agentFn | false /** @property nodeFilter A custom function used by the connection pool to determine which nodes are qualified to receive a request - * @defaultValue () => true */ + * @defaultValue A function that uses the Connection `roles` property to avoid master-only nodes */ nodeFilter?: nodeFilterFn /** @property nodeSelector A custom function used by the connection pool to determine which node should receive the next request * @defaultValue A "round robin" function that loops sequentially through each node in the pool. */ diff --git a/test/unit/client.test.ts b/test/unit/client.test.ts index d7679a7fe..d09b56e8a 100644 --- a/test/unit/client.test.ts +++ b/test/unit/client.test.ts @@ -77,6 +77,31 @@ test('Missing node(s)', t => { t.end() }) +test('multi nodes with roles, using default node filter', async t => { + const client = new Client({ + nodes: [ + { + url: new URL('http://node1:9200'), + roles: { master: true, data: false, ingest: false, ml: false } + }, + { + url: new URL('http://node2:9200'), + roles: { master: true, data: true, ingest: false, ml: false } + }, + ] + }) + const conn = client.connectionPool.getConnection({ + now: Date.now() + 1000 * 60 * 3, + requestId: 1, + name: 'elasticsearch-js', + context: null + }) + + t.equal(conn?.url.hostname, 'node2') + + t.end() +}) + test('Custom headers', t => { const client = new Client({ node: 'http://localhost:9200',