generic-pool
Advanced tools
Comparing version 3.0.0-alpha.9 to 3.0.0-beta.1
# Change Log | ||
## [3.0.0] - October xx 2016 | ||
## [3.0.0] - October 30 2016 | ||
- This is pretty big and the migration guide in the README has more detailed set of changes! | ||
@@ -13,2 +13,5 @@ - switch support to nodejs v4 and above | ||
## [2.4.3] - October 15 2016 | ||
- Use domain.bind to preserve domain context (@LewisJEllis) | ||
## [2.4.2] - March 26 2016 | ||
@@ -120,4 +123,8 @@ - Travis now runs and fails lint checks (@kevinburke) | ||
[unreleased]: https://github.com/coopernurse/node-pool/compare/v2.4.2...HEAD | ||
<<<<<<< HEAD | ||
======= | ||
[unreleased]: https://github.com/coopernurse/node-pool/compare/v3.0.0...HEAD | ||
[3.0.0]: https://github.com/coopernurse/node-pool/compare/v2.4.1...v3.0.0 | ||
[2.4.3]: https://github.com/coopernurse/node-pool/compare/v2.4.2...v2.4.3 | ||
[2.4.2]: https://github.com/coopernurse/node-pool/compare/v2.4.1...v2.4.2 | ||
@@ -124,0 +131,0 @@ [2.4.1]: https://github.com/coopernurse/node-pool/compare/v2.4.0...v2.4.1 |
@@ -195,5 +195,3 @@ 'use strict' | ||
* Attempt to resolve an outstanding resource request using an available resource from | ||
* the pool. | ||
* Shuffles things through | ||
* TODO: rename this! | ||
* the pool, or creating new ones | ||
* | ||
@@ -203,4 +201,2 @@ * @private | ||
_dispense () { | ||
// console.log('_dispense called') | ||
/** | ||
@@ -213,4 +209,4 @@ * Local variables for ease of reading/writing | ||
// If there aren't any waiting requests then there is nothing to do | ||
// so lets short-circuit | ||
if (numWaitingClients < 1) { | ||
// console.log('dispense bailing - no waiting requests') | ||
return | ||
@@ -222,8 +218,2 @@ } | ||
if (this._config.testOnBorrow === true) { | ||
// console.log('dispense - entering test-on-borrow branch') | ||
// Could all the outstanding clients be fulfilled by resources under going test-on-borrow | ||
if (numWaitingClients <= this._testOnBorrowResources.size) { | ||
// console.log('dispense bailing - all waiting requests could be fulfilled by resources in test-on-borrow') | ||
return | ||
} | ||
// how many available resources do we need to shift into test | ||
@@ -235,3 +225,2 @@ const desiredNumberOfResourcesToMoveIntoTest = numWaitingClients - this._testOnBorrowResources.size | ||
} | ||
// console.log('dispense - leaving test-on-borrow branch') | ||
} | ||
@@ -247,15 +236,6 @@ | ||
if (resourceShortfall > 0) { | ||
// console.log('dispense - entering resource shortfall branch') | ||
const spareResourceCapacity = this._config.max - (this._allObjects.size + this._factoryCreateOperations.size) | ||
if (spareResourceCapacity < 1) { | ||
// console.log('not enough allocable resources to satisfy all waiting clients and at max capacity') | ||
} | ||
const actualNumberOfResourcesToCreate = Math.min(spareResourceCapacity, resourceShortfall) | ||
for (let i = 0; actualNumberOfResourcesToCreate > i; i++) { | ||
this._createResource() | ||
} | ||
// console.log('dispense - leaving resource shortfall branch') | ||
const spareResourceCapacity = this._config.max - (this._allObjects.size + this._factoryCreateOperations.size) | ||
const actualNumberOfResourcesToCreate = Math.min(spareResourceCapacity, resourceShortfall) | ||
for (let i = 0; actualNumberOfResourcesToCreate > i; i++) { | ||
this._createResource() | ||
} | ||
@@ -265,3 +245,2 @@ | ||
if (this._config.testOnBorrow === false) { | ||
// console.log('dispense - entering non test-on-borrow branch') | ||
const actualNumberOfResourcesToDispatch = Math.min(this._availableObjects.length, numWaitingClients) | ||
@@ -271,5 +250,3 @@ for (let i = 0; actualNumberOfResourcesToDispatch > i; i++) { | ||
} | ||
// console.log('dispense - leaving non test-on-borrow branch') | ||
} | ||
// console.log('dispense finished') | ||
} | ||
@@ -318,3 +295,2 @@ | ||
}) | ||
.then() | ||
} | ||
@@ -384,3 +360,3 @@ | ||
this._scheduledEviction = setTimeout(() => { | ||
this.evict() | ||
this._evict() | ||
this._scheduleEvictorRun() | ||
@@ -551,2 +527,3 @@ }, this._config.evictionRunIntervalMillis) | ||
} | ||
// TODO: we should handle factory.destroy rejecting... | ||
return this._Promise.all(this._factoryDestroyOperations) | ||
@@ -556,45 +533,2 @@ } | ||
/** | ||
* Decorates a function to use an acquired resource from the object pool when called. | ||
* | ||
* @param {Function} decorated | ||
* The decorated function, accepting a resource as the first argument and | ||
* (optionally) a callback as the final argument. | ||
* | ||
* @param {Number} priority | ||
* Optional. Integer between 0 and (priorityRange - 1). Specifies the priority | ||
* of the caller if there are no available resources. Lower numbers mean higher | ||
* priority. | ||
*/ | ||
pooled (decorated, priority) { | ||
const self = this | ||
return function () { | ||
const callerArgs = arguments | ||
const callerCallback = callerArgs[callerArgs.length - 1] | ||
const callerHasCallback = typeof callerCallback === 'function' | ||
self.acquire(priority) | ||
.then(_onAcquire) | ||
.catch(function (err) { | ||
if (callerHasCallback) { | ||
callerCallback(err) | ||
} | ||
}) | ||
function _onAcquire (resource) { | ||
function _wrappedCallback () { | ||
self.release(resource) | ||
if (callerHasCallback) { | ||
callerCallback.apply(null, arguments) | ||
} | ||
} | ||
const args = [resource].concat(Array.prototype.slice.call(callerArgs, 0, callerHasCallback ? -1 : undefined)) | ||
args.push(_wrappedCallback) | ||
decorated.apply(null, args) | ||
} | ||
} | ||
} | ||
/** | ||
* The combined count of the currently created objects and those in the | ||
@@ -601,0 +535,0 @@ * process of being created |
@@ -10,4 +10,2 @@ 'use strict' | ||
this.fifo = true | ||
this.refreshIdle = true | ||
this.reapIntervalMillis = 1000 | ||
this.priorityRange = 1 | ||
@@ -14,0 +12,0 @@ |
@@ -19,4 +19,2 @@ 'use strict' | ||
* maximum number of queued requests allowed after which acquire calls will be rejected | ||
* @param {Number} config.reapIntervalMillis | ||
* Cleanup is scheduled in every `config.reapIntervalMillis` milliseconds. | ||
* @param {Number} config.acquireTimeoutMillis | ||
@@ -27,4 +25,2 @@ * Delay in milliseconds after which the an `acquire` call will fail. optional. | ||
* The range from 1 to be treated as a valid priority | ||
* @param {RefreshIdle} config.refreshIdle | ||
* Should idle resources be destroyed and recreated every idleTimeoutMillis? Default: true. | ||
* @param {Bool} [config.fifo=true] | ||
@@ -55,4 +51,2 @@ * Sets whether the pool has LIFO (last in, first out) behaviour with respect to idle objects. | ||
this.fifo = (typeof opts.fifo === 'boolean') ? opts.fifo : poolDefaults.fifo | ||
this.refreshIdle = ('refreshIdle' in opts) ? opts.refreshIdle : poolDefaults.refreshIdle | ||
this.reapInterval = opts.reapIntervalMillis || poolDefaults.reapIntervalMillis | ||
this.priorityRange = opts.priorityRange || poolDefaults.priorityRange | ||
@@ -59,0 +53,0 @@ |
{ | ||
"name": "generic-pool", | ||
"description": "Generic resource pooling for Node.JS", | ||
"version": "3.0.0-alpha.9", | ||
"version": "3.0.0-beta.1", | ||
"author": "James Cooper <james@bitmechanic.com>", | ||
@@ -50,2 +50,6 @@ "contributors": [ | ||
"email": "james.butler@sandfox.co.uk" | ||
}, | ||
{ | ||
"name": "Lewis J Ellis", | ||
"email": "me@lewisjellis.com" | ||
} | ||
@@ -52,0 +56,0 @@ ], |
@@ -137,4 +137,3 @@ [![build status](https://secure.travis-ci.org/coopernurse/node-pool.png)](http://travis-ci.org/coopernurse/node-pool) | ||
- `maxWaitingClients`: maximum number of queued requests allowed, additional `acquire` calls will be callback with an `err` in a future cycle of the event loop. | ||
- `testOnBorrow`: `boolean`: should the pool validate resources before giving them to clients. Requires that either `factory.validate` or `factory.validateAsync` to be specified. | ||
- `refreshIdle`: `boolean` that specifies whether idle resources at or below the min threshold should be destroyed/re-created. (default=true) | ||
- `testOnBorrow`: `boolean`: should the pool validate resources before giving them to clients. Requires that either `factory.validate` or `factory.validateAsync` to be specified | ||
- `idleTimeoutMillis`: max milliseconds a resource can stay unused in the pool without being borrowed before it should be destroyed (default 30000) | ||
@@ -212,4 +211,6 @@ - `reapIntervalMillis`: interval to check for idle resources (default 1000). (remove me!) | ||
The pool has an evictor (off by default) which will inspect idle items in the pool and `destroy` them if they are too old | ||
The pool has an evictor (off by default) which will inspect idle items in the pool and `destroy` them if they are too old. | ||
By default the evictor does not run, to enable it you must set the `evictionRunIntervalMillis` option to a non-zero value. Once enable the evictor will check at most `numTestsPerEvictionRun` each time, this is to stop it blocking your application if you have lots of resources in the pool. | ||
## Draining | ||
@@ -301,33 +302,4 @@ | ||
To transparently handle object acquisition for a function, | ||
one can use `pooled()`: | ||
This has now been extracted out it's own module [generic-pool-decorator](https://github.com/sandfox/generic-pool-decorator) | ||
```js | ||
var privateFn, publicFn; | ||
publicFn = pool.pooled(privateFn = function(client, arg, cb) { | ||
// Do something with the client and arg. Client is auto-released when cb is called | ||
cb(null, arg); | ||
}); | ||
``` | ||
Keeping both private and public versions of each function allows for pooled | ||
functions to call other pooled functions with the same member. This is a handy | ||
pattern for database transactions: | ||
```js | ||
var privateTop, privateBottom, publicTop, publicBottom; | ||
publicBottom = pool.pooled(privateBottom = function(client, arg, cb) { | ||
//Use client, assumed auto-release | ||
}); | ||
publicTop = pool.pooled(privateTop = function(client, cb) { | ||
// e.g., open a database transaction | ||
privateBottom(client, "arg", function(err, retVal) { | ||
if(err) { return cb(err); } | ||
// e.g., close a transaction | ||
cb(); | ||
}); | ||
}); | ||
``` | ||
## Pool info | ||
@@ -334,0 +306,0 @@ |
@@ -12,4 +12,3 @@ 'use strict' | ||
// const config = { | ||
// max: 1, | ||
// refreshIdle: false, | ||
// max: 1 | ||
// } | ||
@@ -42,4 +41,3 @@ | ||
// min: 1, | ||
// max: 2, | ||
// refreshIdle: false | ||
// max: 2 | ||
// } | ||
@@ -61,8 +59,4 @@ | ||
const config = { | ||
refreshIdle: false | ||
} | ||
const pool = new Pool(resourceFactory) | ||
const pool = new Pool(resourceFactory, config) | ||
t.equal(1, pool.max) | ||
@@ -78,3 +72,2 @@ t.equal(0, pool.min) | ||
const config = { | ||
refreshIdle: false, | ||
min: 'asf', | ||
@@ -95,3 +88,2 @@ max: [] | ||
const config = { | ||
refreshIdle: false, | ||
min: 5, | ||
@@ -118,3 +110,2 @@ max: 3 | ||
max: 1, | ||
refreshIdle: false, | ||
priorityRange: 2 | ||
@@ -167,4 +158,3 @@ } | ||
// const config | ||
// max: 2, | ||
// refreshIdle: false | ||
// max: 2 | ||
// } | ||
@@ -199,2 +189,25 @@ | ||
tap.test('evictor removes instances on idletimeout', function (t) { | ||
const resourceFactory = new ResourceFactory() | ||
const config = { | ||
min: 2, | ||
max: 2, | ||
idleTimeoutMillis: 50, | ||
evictionRunIntervalMillis: 10 | ||
} | ||
const pool = new Pool(resourceFactory, config) | ||
setTimeout(function () { | ||
pool.acquire() | ||
.then((res) => { | ||
t.ok(res.id > 1) | ||
return pool.release(res) | ||
}) | ||
.then(() => { | ||
utils.stopPool(pool) | ||
t.end() | ||
}) | ||
}, 120) | ||
}) | ||
tap.test('tests drain', function (t) { | ||
@@ -341,171 +354,2 @@ const count = 5 | ||
tap.test('pooled decorator should acquire and release', function (t) { | ||
// FIXME: assertion count should probably be replaced with t.plan? | ||
let assertionCount = 0 | ||
const resourceFactory = new ResourceFactory() | ||
const config = { | ||
max: 1, | ||
refreshIdle: false | ||
} | ||
const pool = new Pool(resourceFactory, config) | ||
const pooledFn = pool.pooled(function (client, cb) { | ||
t.equal(typeof client.id, 'number') | ||
t.equal(pool.size, 1) | ||
assertionCount += 2 | ||
cb() | ||
}) | ||
t.equal(pool.size, 0) | ||
assertionCount += 1 | ||
pooledFn(function (err) { | ||
// FIXME: what is even happening in this block? | ||
if (err) { throw err } | ||
t.ok(true) | ||
assertionCount += 1 | ||
}) | ||
utils.stopPool(pool) | ||
.then(function () { | ||
t.equal(assertionCount, 4) | ||
t.end() | ||
}) | ||
}) | ||
tap.test('pooled decorator should pass arguments and return values', function (t) { | ||
// FIXME: assertion count should probably be replaced with t.plan? | ||
let assertionCount = 0 | ||
const resourceFactory = new ResourceFactory() | ||
const config = { | ||
max: 1 | ||
} | ||
const pool = new Pool(resourceFactory, config) | ||
const pooledFn = pool.pooled(function (client, arg1, arg2, cb) { | ||
t.equal(arg1, 'First argument') | ||
t.equal(arg2, 'Second argument') | ||
assertionCount += 2 | ||
cb(null, 'First return', 'Second return') | ||
}) | ||
pooledFn('First argument', 'Second argument', function (err, retVal1, retVal2) { | ||
if (err) { throw err } | ||
t.equal(retVal1, 'First return') | ||
t.equal(retVal2, 'Second return') | ||
assertionCount += 2 | ||
}) | ||
utils.stopPool(pool) | ||
.then(function () { | ||
t.equal(assertionCount, 4) | ||
t.end() | ||
}) | ||
}) | ||
// FIXME: I'm not really sure what this testing... | ||
tap.test('pooled decorator should allow undefined callback', function (t) { | ||
let assertionCount = 0 | ||
const resourceFactory = new ResourceFactory() | ||
const config = { | ||
max: 1, | ||
refreshIdle: false | ||
} | ||
const pool = new Pool(resourceFactory, config) | ||
const pooledFn = pool.pooled(function (client, arg, cb) { | ||
t.equal(arg, 'Arg!') | ||
assertionCount += 1 | ||
cb() | ||
}) | ||
pooledFn('Arg!') | ||
t.equal(pool.size, 1) | ||
utils.stopPool(pool) | ||
.then(function () { | ||
t.equal(assertionCount, 1) | ||
t.end() | ||
}) | ||
}) | ||
tap.test('pooled decorator should not forward pool factory errors', function (t) { | ||
let assertionCount = 0 | ||
let attempts = 0 | ||
const resourceFactory = { | ||
create: function () { | ||
attempts++ | ||
if (attempts <= 1) { | ||
return Promise.reject(new Error('Error occurred.')) | ||
} else { | ||
return Promise.resolve({ id: attempts }) | ||
} | ||
}, | ||
destroy: function (client) { return Promise.resolve() } | ||
} | ||
const pool = new Pool(resourceFactory, | ||
{ | ||
max: 1 | ||
}) | ||
const pooledFn = pool.pooled(function (resource, cb) { | ||
cb() | ||
}) | ||
pooledFn(function (err, obj) { | ||
t.error(err, 'Pool error was forwarded!') | ||
assertionCount++ | ||
}) | ||
utils.stopPool(pool) | ||
.then(function () { | ||
t.equal(assertionCount, 1) | ||
t.end() | ||
}) | ||
}) | ||
tap.test('pooled decorator should forward pool acquire timeout errors', function (t) { | ||
let assertionCount = 0 | ||
let attempts = 0 | ||
const resourceFactory = { | ||
create: function () { | ||
attempts++ | ||
return new Promise(function (resolve) { | ||
setTimeout(function () { | ||
resolve({ id: attempts }) | ||
}, 20) | ||
}) | ||
}, | ||
destroy: function (client) { return Promise.resolve() } | ||
} | ||
const pool = new Pool(resourceFactory, | ||
{ | ||
acquireTimeoutMillis: 10, | ||
max: 1 | ||
}) | ||
const pooledFn = pool.pooled(function (resource, cb) { | ||
cb() | ||
}) | ||
pooledFn(function (err, obj) { | ||
t.match(err, /ResourceRequest timed out/) | ||
assertionCount++ | ||
}) | ||
utils.stopPool(pool) | ||
.then(function () { | ||
t.equal(assertionCount, 1) | ||
t.end() | ||
}) | ||
}) | ||
tap.test('getPoolSize', function (t) { | ||
@@ -515,4 +359,3 @@ let assertionCount = 0 | ||
const config = { | ||
max: 2, | ||
refreshIdle: false | ||
max: 2 | ||
} | ||
@@ -566,4 +409,3 @@ | ||
const config = { | ||
max: 2, | ||
refreshIdle: false | ||
max: 2 | ||
} | ||
@@ -708,4 +550,3 @@ | ||
const config = { | ||
max: 1, | ||
refreshIdle: false | ||
max: 1 | ||
} | ||
@@ -712,0 +553,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
83305
1980
362