Child client support (#768)
With this pr we introduce the `client.child` API, which returns a new client instance that shares the connection pool with the parent client.
This feature can be handy if you need to have multiple client instances with different configurations, but with a shared connection pool.
Example:
```js
const { Client } = require('@elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' })
const child = client.child({
headers: { 'x-foo': 'bar' },
requestTimeout: 1000
})
client.info(console.log)
child.info(console.log)
```
**Open questions:**
* Currently, the event emitter is shared between the parent and the child(ren), is it ok?
* Currently, if you extend the parent client, the child client will have the same extensions, while if the child client adds an extension, the parent client will not be extended. Is it ok?
**Caveats:**
* You can override _any_ option except for the connection pool specific options (`ssl`, `agent`, `pingTimeout`, `Connection`, and `resurrectStrategy`).
* You can't specify a new `Connection` class.
* If you call `close` in any of the parent/child clients, every client will be closed.
_Note: the `nodeFilter` and `nodeSelector` options are now `Transport` options and no longer `ConnectionPool` options._
This commit is contained in:
committed by
GitHub
parent
66e8d61476
commit
5b856cd4c2
194
test/unit/child.test.js
Normal file
194
test/unit/child.test.js
Normal file
@ -0,0 +1,194 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const { Client, errors } = require('../../index')
|
||||
const {
|
||||
buildServer,
|
||||
connection: { MockConnection }
|
||||
} = require('../utils')
|
||||
|
||||
test('Should create a child client (headers check)', t => {
|
||||
t.plan(4)
|
||||
|
||||
var count = 0
|
||||
function handler (req, res) {
|
||||
if (count++ === 0) {
|
||||
t.match(req.headers, { 'x-foo': 'bar' })
|
||||
} else {
|
||||
t.match(req.headers, { 'x-baz': 'faz' })
|
||||
}
|
||||
res.setHeader('Content-Type', 'application/json;utf=8')
|
||||
res.end(JSON.stringify({ hello: 'world' }))
|
||||
}
|
||||
|
||||
buildServer(handler, ({ port }, server) => {
|
||||
const client = new Client({
|
||||
node: `http://localhost:${port}`,
|
||||
headers: { 'x-foo': 'bar' }
|
||||
})
|
||||
const child = client.child({
|
||||
headers: { 'x-baz': 'faz' }
|
||||
})
|
||||
|
||||
client.info((err, res) => {
|
||||
t.error(err)
|
||||
child.info((err, res) => {
|
||||
t.error(err)
|
||||
server.stop()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should create a child client (timeout check)', t => {
|
||||
t.plan(2)
|
||||
|
||||
function handler (req, res) {
|
||||
setTimeout(() => {
|
||||
res.setHeader('Content-Type', 'application/json;utf=8')
|
||||
res.end(JSON.stringify({ hello: 'world' }))
|
||||
}, 50)
|
||||
}
|
||||
|
||||
buildServer(handler, ({ port }, server) => {
|
||||
const client = new Client({ node: `http://localhost:${port}` })
|
||||
const child = client.child({ requestTimeout: 25, maxRetries: 0 })
|
||||
|
||||
client.info((err, res) => {
|
||||
t.error(err)
|
||||
child.info((err, res) => {
|
||||
t.true(err instanceof errors.TimeoutError)
|
||||
server.stop()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Client extensions', t => {
|
||||
t.test('One level', t => {
|
||||
t.plan(1)
|
||||
|
||||
const client = new Client({ node: 'http://localhost:9200' })
|
||||
client.extend('utility.index', () => {
|
||||
return () => t.ok('called')
|
||||
})
|
||||
|
||||
const child = client.child()
|
||||
child.utility.index()
|
||||
})
|
||||
|
||||
t.test('Two levels', t => {
|
||||
t.plan(2)
|
||||
|
||||
const client = new Client({ node: 'http://localhost:9200' })
|
||||
client.extend('utility.index', () => {
|
||||
return () => t.ok('called')
|
||||
})
|
||||
|
||||
const child = client.child()
|
||||
child.extend('utility.search', () => {
|
||||
return () => t.ok('called')
|
||||
})
|
||||
|
||||
const grandchild = child.child()
|
||||
grandchild.utility.index()
|
||||
grandchild.utility.search()
|
||||
})
|
||||
|
||||
t.test('The child should not extend the parent', t => {
|
||||
t.plan(1)
|
||||
|
||||
const client = new Client({ node: 'http://localhost:9200' })
|
||||
const child = client.child()
|
||||
|
||||
child.extend('utility.index', () => {
|
||||
return () => t.fail('Should not be called')
|
||||
})
|
||||
|
||||
try {
|
||||
client.utility.index()
|
||||
} catch (err) {
|
||||
t.ok(err)
|
||||
}
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Should share the event emitter', t => {
|
||||
t.test('One level', t => {
|
||||
t.plan(2)
|
||||
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
Connection: MockConnection
|
||||
})
|
||||
const child = client.child()
|
||||
|
||||
client.on('response', (err, meta) => {
|
||||
t.error(err)
|
||||
})
|
||||
|
||||
child.info((err, res) => {
|
||||
t.error(err)
|
||||
})
|
||||
})
|
||||
|
||||
t.test('Two levels', t => {
|
||||
t.plan(2)
|
||||
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
Connection: MockConnection
|
||||
})
|
||||
const child = client.child()
|
||||
const grandchild = child.child()
|
||||
|
||||
client.on('response', (err, meta) => {
|
||||
t.error(err)
|
||||
})
|
||||
|
||||
grandchild.info((err, res) => {
|
||||
t.error(err)
|
||||
})
|
||||
})
|
||||
|
||||
t.test('Child listener - one level', t => {
|
||||
t.plan(2)
|
||||
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
Connection: MockConnection
|
||||
})
|
||||
const child = client.child()
|
||||
|
||||
child.on('response', (err, meta) => {
|
||||
t.error(err)
|
||||
})
|
||||
|
||||
child.info((err, res) => {
|
||||
t.error(err)
|
||||
})
|
||||
})
|
||||
|
||||
t.test('Child listener - two levels', t => {
|
||||
t.plan(2)
|
||||
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
Connection: MockConnection
|
||||
})
|
||||
const child = client.child()
|
||||
const grandchild = child.child()
|
||||
|
||||
child.on('response', (err, meta) => {
|
||||
t.error(err)
|
||||
})
|
||||
|
||||
grandchild.info((err, res) => {
|
||||
t.error(err)
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
Reference in New Issue
Block a user