diff --git a/CHANGELOG.md b/CHANGELOG.md index f7f7469e2..787658e11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,8 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Remove guidance on using npm and switch completely to yarn in developer_guide ([#439](https://github.com/opensearch-project/opensearch-js/issues/435)) - Change coverage, compatability, integration, integration with unreleased Open Search, node ci, bundler tests not to run on documentation change ([441](https://github.com/opensearch-project/opensearch-js/pull/441)) - Change the Windows yarn installation troubleshoot steps ([455](https://github.com/opensearch-project/opensearch-js/issues/455)) +- Make `callback` arg in `BaseConnectionPool`, `CloudConnectionPool` and `ConnectionPool` optional ([#451](https://github.com/opensearch-project/opensearch-js/pull/451)) + ### Deprecated - Remove deprecation warnings in bulk.test.js ([#434](https://github.com/opensearch-project/opensearch-js/issues/434)) diff --git a/USER_GUIDE.md b/USER_GUIDE.md index 579c170e3..d917f93f6 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -10,6 +10,7 @@ - [Search for the Document](#search-for-the-document) - [Delete the document](#delete-the-document) - [Delete the index](#delete-the-index) + - [Empty all Pool Connections](#empty-all-pool-connections) ## Initializing a Client @@ -87,7 +88,7 @@ const { AwsSigv4Signer } = require('@opensearch-project/opensearch/aws'); const client = new Client({ ...AwsSigv4Signer({ region: 'us-east-1', - service: 'es', // 'aoss' for OpenSearch Serverless + service: 'es', // 'aoss' for OpenSearch Serverless // Must return a Promise that resolve to an AWS.Credentials object. // This function is used to acquire the credentials when the client start and // when the credentials are expired. @@ -249,4 +250,18 @@ console.log('Deleting all PITs:'); var response = await client.deleteAllPits(); console.log(response.body); -``` \ No newline at end of file +``` + +## Empty all Pool Connections + +```javascript +var pool = new ConnectionPool({ Connection }); +pool.addConnection('http://localhost:9200/'); +pool.addConnection('http://localhost:9201/'); + +pool.empty(); +// OR +pool.empty(() => { + // Do something after emptying the pool +}); +``` diff --git a/lib/pool/BaseConnectionPool.js b/lib/pool/BaseConnectionPool.js index c2a901f64..30c5ad8df 100644 --- a/lib/pool/BaseConnectionPool.js +++ b/lib/pool/BaseConnectionPool.js @@ -32,6 +32,7 @@ const { URL } = require('url'); const debug = require('debug')('opensearch'); const Connection = require('../Connection'); +const { ConfigurationError } = require('../errors'); const noop = () => {}; class BaseConnectionPool { @@ -64,6 +65,9 @@ class BaseConnectionPool { * Creates a new connection instance. */ createConnection(opts) { + if (opts instanceof Connection) { + throw new ConfigurationError('The argument provided is already a Connection instance.'); + } if (typeof opts === 'string') { opts = this.urlToHost(opts); } @@ -102,18 +106,25 @@ class BaseConnectionPool { */ addConnection(opts) { if (Array.isArray(opts)) { - return opts.forEach((o) => this.addConnection(o)); + opts.forEach((o) => this.addConnection(o)); + return; } - if (typeof opts === 'string') { opts = this.urlToHost(opts); } - const connectionById = this.connections.find((c) => c.id === opts.id); - const connectionByUrl = this.connections.find((c) => c.id === opts.url.href); + const connectionId = opts.id; + const connectionUrl = opts.url.href; + + if (connectionId || connectionUrl) { + const connectionById = this.connections.find((c) => c.id === connectionId); + const connectionByUrl = this.connections.find((c) => c.id === connectionUrl); - if (connectionById || connectionByUrl) { - throw new Error(`Connection with id '${opts.id || opts.url.href}' is already present`); + if (connectionById || connectionByUrl) { + throw new ConfigurationError( + `Connection with id '${connectionId || connectionUrl}' is already present` + ); + } } this.update([...this.connections, opts]); @@ -133,10 +144,8 @@ class BaseConnectionPool { /** * Empties the connection pool. - * - * @returns {ConnectionPool} */ - empty(callback) { + empty(callback = noop) { debug('Emptying the connection pool'); let openConnections = this.size; this.connections.forEach((connection) => { diff --git a/lib/pool/CloudConnectionPool.js b/lib/pool/CloudConnectionPool.js index 82f2001b9..d512c6f80 100644 --- a/lib/pool/CloudConnectionPool.js +++ b/lib/pool/CloudConnectionPool.js @@ -30,6 +30,7 @@ 'use strict'; const BaseConnectionPool = require('./BaseConnectionPool'); +const noop = () => {}; class CloudConnectionPool extends BaseConnectionPool { constructor(opts) { @@ -49,9 +50,8 @@ class CloudConnectionPool extends BaseConnectionPool { /** * Empties the connection pool. * - * @returns {ConnectionPool} */ - empty(callback) { + empty(callback = noop) { super.empty(() => { this.cloudConnection = null; callback(); diff --git a/lib/pool/ConnectionPool.js b/lib/pool/ConnectionPool.js index b36abd324..21f728543 100644 --- a/lib/pool/ConnectionPool.js +++ b/lib/pool/ConnectionPool.js @@ -227,7 +227,7 @@ class ConnectionPool extends BaseConnectionPool { * * @returns {ConnectionPool} */ - empty(callback) { + empty(callback = noop) { super.empty(() => { this.dead = []; callback(); diff --git a/lib/pool/index.d.ts b/lib/pool/index.d.ts index fe6954362..97cbde41f 100644 --- a/lib/pool/index.d.ts +++ b/lib/pool/index.d.ts @@ -31,7 +31,7 @@ import { URL } from 'url'; import { SecureContextOptions } from 'tls'; -import Connection, { AgentOptions } from '../Connection'; +import Connection, { AgentOptions, ConnectionOptions } from '../Connection'; import { nodeFilterFn, nodeSelectorFn } from '../Transport'; interface BaseConnectionPoolOptions { @@ -121,7 +121,7 @@ declare class BaseConnectionPool { * @param {object|string} host * @returns {ConnectionPool} */ - addConnection(opts: any): Connection; + addConnection(opts: string | ConnectionOptions | ConnectionOptions[]): Connection; /** * Removes a new connection to the pool. * @@ -132,16 +132,15 @@ declare class BaseConnectionPool { /** * Empties the connection pool. * - * @returns {ConnectionPool} */ - empty(): this; + empty(callback?: () => void): void; /** * Update the ConnectionPool with new connections. * * @param {array} array of connections * @returns {ConnectionPool} */ - update(connections: any[]): this; + update(connections: Connection[]): this; /** * Transforms the nodes objects to a host object. * @@ -155,7 +154,7 @@ declare class BaseConnectionPool { * @param {string} url * @returns {object} host */ - urlToHost(url: string): { url: URL }; + urlToHost(url: string): ConnectionOptions; } declare class ConnectionPool extends BaseConnectionPool { @@ -183,12 +182,35 @@ declare class ConnectionPool extends BaseConnectionPool { opts: resurrectOptions, callback?: (isAlive: boolean | null, connection: Connection | null) => void ): void; + + /** + * Empties the connection pool. + */ + empty(callback?: () => void): void; + /** + * Update the ConnectionPool with new connections. + * + * @param {array} array of connections + * @returns {ConnectionPool} + */ + update(connections: Connection[]): this; } declare class CloudConnectionPool extends BaseConnectionPool { cloudConnection: Connection | null; constructor(opts?: BaseConnectionPoolOptions); getConnection(): Connection | null; + /** + * Empties the connection pool. + */ + empty(callback?: () => void): void; + /** + * Update the ConnectionPool with new connections. + * + * @param {array} array of connections + * @returns {ConnectionPool} + */ + update(connections: Connection[]): this; } declare function defaultNodeFilter(node: Connection): boolean; diff --git a/test/types/connection-pool.test-d.ts b/test/types/connection-pool.test-d.ts index 1b35c41db..e2df1334f 100644 --- a/test/types/connection-pool.test-d.ts +++ b/test/types/connection-pool.test-d.ts @@ -30,6 +30,7 @@ import { expectType, expectAssignable } from 'tsd'; import { URL } from 'url'; import { BaseConnectionPool, ConnectionPool, CloudConnectionPool, Connection } from '../../'; +import { ConnectionOptions } from '../../lib/Connection'; { const pool = new BaseConnectionPool({ @@ -59,12 +60,12 @@ import { BaseConnectionPool, ConnectionPool, CloudConnectionPool, Connection } f now: Date.now(), }) ); - expectType(pool.addConnection({})); + expectType(pool.addConnection({ url: new URL('url') })); expectType(pool.removeConnection(new Connection())); - expectType(pool.empty()); + expectType(pool.empty()); expectType(pool.update([])); expectType(pool.nodesToHost([], 'https')); - expectType<{ url: URL }>(pool.urlToHost('url')); + expectType(pool.urlToHost('url')); } { @@ -99,12 +100,12 @@ import { BaseConnectionPool, ConnectionPool, CloudConnectionPool, Connection } f now: Date.now(), }) ); - expectType(pool.addConnection({})); + expectType(pool.addConnection({ url: new URL('url') })); expectAssignable(pool.removeConnection(new Connection())); - expectAssignable(pool.empty()); + expectType(pool.empty()); expectAssignable(pool.update([])); expectType(pool.nodesToHost([], 'https')); - expectType<{ url: URL }>(pool.urlToHost('url')); + expectType(pool.urlToHost('url')); expectType( pool.resurrect({ now: Date.now(), diff --git a/test/unit/base-connection-pool.test.js b/test/unit/base-connection-pool.test.js index 8af26a393..5b2ea5fc7 100644 --- a/test/unit/base-connection-pool.test.js +++ b/test/unit/base-connection-pool.test.js @@ -70,6 +70,15 @@ test('API', (t) => { t.end(); }); + t.test('addConnection with only URL', (t) => { + const pool = new BaseConnectionPool({ Connection }); + const href = 'http://localhost:9200/'; + pool.addConnection({ url: new URL(href) }); + t.ok(pool.connections.find((c) => c.id === href) instanceof Connection); + t.equal(pool.connections.find((c) => c.id === href).status, Connection.statuses.ALIVE); + t.end(); + }); + t.test('markDead', (t) => { const pool = new BaseConnectionPool({ Connection, sniffEnabled: true }); const href = 'http://localhost:9200/'; @@ -122,6 +131,31 @@ test('API', (t) => { }); }); + t.test('empty with no callback', (t) => { + const pool = new BaseConnectionPool({ Connection }); + pool.addConnection('http://localhost:9200/'); + pool.addConnection('http://localhost:9201/'); + pool.empty(); + t.equal(pool.size, 0); + t.end(); + }); + + t.test('call empty twice', (t) => { + const pool = new BaseConnectionPool({ Connection }); + pool.addConnection('http://localhost:9200/'); + pool.addConnection('http://localhost:9201/'); + try { + pool.empty(); + pool.empty(() => { + t.equal(pool.size, 0); + t.pass(); + }); + } catch (error) { + t.fail('Should not throw'); + } + t.end(); + }); + t.test('urlToHost', (t) => { const pool = new BaseConnectionPool({ Connection }); const url = 'http://localhost:9200'; @@ -581,5 +615,18 @@ test('API', (t) => { } }); + t.test('Create Connection with a Connection instance', (t) => { + t.plan(1); + const pool = new BaseConnectionPool({ Connection }); + const conn = pool.createConnection('http://localhost:9200'); + pool.connections.push(conn); + try { + pool.createConnection(conn); + t.fail('Should throw'); + } catch (err) { + t.pass(); + } + }); + t.end(); }); diff --git a/test/unit/cloud-connection-pool.test.js b/test/unit/cloud-connection-pool.test.js index ea90d91e6..f251f4393 100644 --- a/test/unit/cloud-connection-pool.test.js +++ b/test/unit/cloud-connection-pool.test.js @@ -56,3 +56,12 @@ test('pool.empty should reset cloudConnection', (t) => { t.end(); }); }); + +test('empty with no callback', (t) => { + const pool = new CloudConnectionPool({ Connection }); + pool.addConnection('http://localhost:9200/'); + t.ok(pool.cloudConnection instanceof Connection); + pool.empty(); + t.equal(pool.cloudConnection, null); + t.end(); +}); diff --git a/test/unit/connection-pool.test.js b/test/unit/connection-pool.test.js index 4c638126a..a571b4ae5 100644 --- a/test/unit/connection-pool.test.js +++ b/test/unit/connection-pool.test.js @@ -325,6 +325,16 @@ test('API', (t) => { }); }); + t.test('empty with no callback', (t) => { + const pool = new ConnectionPool({ Connection }); + pool.addConnection('http://localhost:9200/'); + pool.addConnection('http://localhost:9201/'); + pool.empty(); + t.equal(pool.size, 0); + t.same(pool.dead, []); + t.end(); + }); + t.test('urlToHost', (t) => { const pool = new ConnectionPool({ Connection }); const url = 'http://localhost:9200';