diff --git a/README.md b/README.md index b32dfc4dc08..e5c2771c2ad 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,15 @@ Options: This value may be overriden by keep-alive hints from the server. Default: `4e3` milliseconds (4s). +- `maxIdleTimeout: Number`, the maximum allowed `idleTimeout` when overriden by + keep-alive hints from the server. + Default: `600e3` milliseconds (10min). + +- `keepAliveTimeoutThreshold: Number`, a number subtracted from server keep-alive hints + when overriding `idleTimeout` to account for timing inaccuries caused by e.g. + transport latency. + Default: `1e3` milliseconds (1s). + - `requestTimeout: Number`, the timeout after which a request will time out. Monitors time between request being enqueued and receiving a response. Use `0` to disable it entirely. diff --git a/lib/client.js b/lib/client.js index 708e5b8274e..3ffc1d071b0 100644 --- a/lib/client.js +++ b/lib/client.js @@ -49,7 +49,9 @@ const { kEnqueue, kKeepAliveTimeout, kMaxHeadersSize, - kHeadersTimeout + kHeadersTimeout, + kMaxIdleTimeout, + kKeepAliveTimeoutThreshold } = require('./symbols') const makeStream = require('./client-stream') const makeRequest = require('./client-request') @@ -69,6 +71,8 @@ class Client extends EventEmitter { headersTimeout, socketTimeout, idleTimeout, + maxIdleTimeout, + keepAliveTimeoutThreshold, socketPath, requestTimeout, pipelining, @@ -120,6 +124,18 @@ class Client extends EventEmitter { throw new InvalidArgumentError('invalid idleTimeout') } + if (idleTimeout != null && (!Number.isFinite(idleTimeout) || idleTimeout <= 0)) { + throw new InvalidArgumentError('invalid idleTimeout') + } + + if (maxIdleTimeout != null && (!Number.isFinite(maxIdleTimeout) || maxIdleTimeout <= 0)) { + throw new InvalidArgumentError('invalid maxIdleTimeout') + } + + if (keepAliveTimeoutThreshold != null && !Number.isFinite(keepAliveTimeoutThreshold)) { + throw new InvalidArgumentError('invalid keepAliveTimeoutThreshold') + } + if (requestTimeout != null && !Number.isFinite(requestTimeout)) { throw new InvalidArgumentError('invalid requestTimeout') } @@ -136,7 +152,9 @@ class Client extends EventEmitter { this[kUrl] = url this[kSocketPath] = socketPath this[kSocketTimeout] = socketTimeout == null ? 30e3 : socketTimeout + this[kMaxIdleTimeout] = maxIdleTimeout == null ? 600e3 : maxIdleTimeout this[kIdleTimeout] = idleTimeout == null ? 4e3 : idleTimeout + this[kKeepAliveTimeoutThreshold] = keepAliveTimeoutThreshold == null ? 1e3 : keepAliveTimeoutThreshold this[kKeepAliveTimeout] = this[kIdleTimeout] this[kRequestTimeout] = requestTimeout == null ? 30e3 : requestTimeout this[kClosed] = false @@ -494,12 +512,14 @@ class Parser extends HTTPParser { if (headers['keep-alive']) { const m = headers['keep-alive'].match(/timeout=(\d+)/) if (m) { - const timeout = Number(m[1]) - if (!timeout) { + const keepAliveTimeout = Math.min( + Number(m[1]) * 1000 - client[kKeepAliveTimeoutThreshold], + client[kMaxIdleTimeout] + ) + if (!keepAliveTimeout || keepAliveTimeout < 1e3) { client[kReset] = true } else { - // Set timeout to 500ms less than hint to account for timing inaccuracies. - client[kKeepAliveTimeout] = timeout * 1000 - 500 + client[kKeepAliveTimeout] = keepAliveTimeout } } } else { diff --git a/lib/pool.js b/lib/pool.js index dae4397e444..9738e47f256 100644 --- a/lib/pool.js +++ b/lib/pool.js @@ -12,12 +12,7 @@ const { class Pool { constructor (url, { connections, - maxAbortedPayload, - socketTimeout, - requestTimeout, - pipelining, - tls, - socketPath + ...options } = {}) { if (connections != null && (!Number.isFinite(connections) || connections <= 0)) { throw new InvalidArgumentError('invalid connections') @@ -25,14 +20,7 @@ class Pool { this[kClients] = Array.from({ length: connections || 10 - }, () => new Client(url, { - maxAbortedPayload, - socketTimeout, - requestTimeout, - pipelining, - tls, - socketPath - })) + }, () => new Client(url, options)) } /* istanbul ignore next: use by benchmark */ diff --git a/lib/symbols.js b/lib/symbols.js index 7af2f914d52..70023fcdd11 100644 --- a/lib/symbols.js +++ b/lib/symbols.js @@ -6,6 +6,8 @@ module.exports = { kConnect: Symbol('connect'), kSocketTimeout: Symbol('socket timeout'), kIdleTimeout: Symbol('idle timeout'), + kMaxIdleTimeout: Symbol('max idle timeout'), + kKeepAliveTimeoutThreshold: Symbol('keep alive threshold'), kRequestTimeout: Symbol('request timeout'), kKeepAliveTimeout: Symbol('keep alive timeout'), kServerName: Symbol('server name'),