Socket
Socket
Sign inDemoInstall

generic-pool

Package Overview
Dependencies
Maintainers
2
Versions
74
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

generic-pool - npm Package Compare versions

Comparing version 3.2.0 to 3.3.0

.eslintignore

12

.eslintrc.js
module.exports = {
"extends": "standard",
"plugins": [
"standard"
]
};
parserOptions: { ecmaVersion: 6 },
plugins: ["prettier"],
rules: {
"prettier/prettier": "error"
},
extends: ["prettier"]
};
# Change Log
## [3.3.0] - December 27 2017
- add `use` method to simplify basic pool usage (@san00)
## [3.2.0] - October 15 2017

@@ -164,3 +167,4 @@ - add `isBorrowedResource` method to check if objects are currently on loan from pool (@C-h-e-r-r-y)

=======
[unreleased]: https://github.com/coopernurse/node-pool/compare/v3.2.0...HEAD
[unreleased]: https://github.com/coopernurse/node-pool/compare/v3.3.0...HEAD
[3.3.0]: https://github.com/coopernurse/node-pool/compare/v3.2.0...v3.3.0
[3.2.0]: https://github.com/coopernurse/node-pool/compare/v3.1.8...v3.2.0

@@ -167,0 +171,0 @@ [3.1.8]: https://github.com/coopernurse/node-pool/compare/v3.1.7...v3.1.8

@@ -1,14 +0,13 @@

const Pool = require('./lib/Pool')
const Deque = require('./lib/Deque')
const PriorityQueue = require('./lib/PriorityQueue')
const DefaultEvictor = require('./lib/DefaultEvictor')
const Pool = require("./lib/Pool");
const Deque = require("./lib/Deque");
const PriorityQueue = require("./lib/PriorityQueue");
const DefaultEvictor = require("./lib/DefaultEvictor");
module.exports = {
Pool: Pool,
Pool: Pool,
Deque: Deque,
PriorityQueue: PriorityQueue,
DefaultEvictor: DefaultEvictor,
createPool: function(factory, config){
return new Pool(DefaultEvictor, Deque, PriorityQueue, factory, config)
createPool: function(factory, config) {
return new Pool(DefaultEvictor, Deque, PriorityQueue, factory, config);
}
}
};

@@ -1,19 +0,22 @@

'use strict'
"use strict";
class DefaultEvictor {
evict (config, pooledResource, availableObjectsCount) {
const idleTime = Date.now() - pooledResource.lastIdleTime
evict(config, pooledResource, availableObjectsCount) {
const idleTime = Date.now() - pooledResource.lastIdleTime;
if (config.softIdleTimeoutMillis < idleTime && config.min < availableObjectsCount) {
return true
if (
config.softIdleTimeoutMillis < idleTime &&
config.min < availableObjectsCount
) {
return true;
}
if (config.idleTimeoutMillis < idleTime) {
return true
return true;
}
return false
return false;
}
}
module.exports = DefaultEvictor
module.exports = DefaultEvictor;

@@ -1,2 +0,2 @@

'use strict'
"use strict";

@@ -8,36 +8,35 @@ /**

class Deferred {
constructor(Promise) {
this._state = Deferred.PENDING;
this._resolve = undefined;
this._reject = undefined;
constructor (Promise) {
this._state = Deferred.PENDING
this._resolve = undefined
this._reject = undefined
this._promise = new Promise((resolve, reject) => {
this._resolve = resolve
this._reject = reject
})
this._resolve = resolve;
this._reject = reject;
});
}
get state () {
return this._state
get state() {
return this._state;
}
get promise () {
return this._promise
get promise() {
return this._promise;
}
reject (reason) {
reject(reason) {
if (this._state !== Deferred.PENDING) {
return
return;
}
this._state = Deferred.REJECTED
this._reject(reason)
this._state = Deferred.REJECTED;
this._reject(reason);
}
resolve (value) {
resolve(value) {
if (this._state !== Deferred.PENDING) {
return
return;
}
this._state = Deferred.FULFILLED
this._resolve(value)
this._state = Deferred.FULFILLED;
this._resolve(value);
}

@@ -47,6 +46,6 @@ }

// TODO: should these really live here? or be a seperate 'state' enum
Deferred.PENDING = 'PENDING'
Deferred.FULFILLED = 'FULFILLED'
Deferred.REJECTED = 'REJECTED'
Deferred.PENDING = "PENDING";
Deferred.FULFILLED = "FULFILLED";
Deferred.REJECTED = "REJECTED";
module.exports = Deferred
module.exports = Deferred;

@@ -1,5 +0,5 @@

'use strict'
"use strict";
const DoublyLinkedList = require('./DoublyLinkedList')
const DequeIterator = require('./DequeIterator')
const DoublyLinkedList = require("./DoublyLinkedList");
const DequeIterator = require("./DequeIterator");
/**

@@ -10,4 +10,4 @@ * DoublyLinkedList backed double ended queue

class Deque {
constructor () {
this._list = new DoublyLinkedList()
constructor() {
this._list = new DoublyLinkedList();
}

@@ -19,11 +19,11 @@

*/
shift () {
shift() {
if (this._length === 0) {
return undefined
return undefined;
}
const node = this._list.head
this._list.remove(node)
const node = this._list.head;
this._list.remove(node);
return node.data
return node.data;
}

@@ -36,6 +36,6 @@

*/
unshift (element) {
const node = DoublyLinkedList.createNode(element)
unshift(element) {
const node = DoublyLinkedList.createNode(element);
this._list.insertBeginning(node)
this._list.insertBeginning(node);
}

@@ -48,6 +48,6 @@

*/
push (element) {
const node = DoublyLinkedList.createNode(element)
push(element) {
const node = DoublyLinkedList.createNode(element);
this._list.insertEnd(node)
this._list.insertEnd(node);
}

@@ -58,23 +58,23 @@

*/
pop () {
pop() {
if (this._length === 0) {
return undefined
return undefined;
}
const node = this._list.tail
this._list.remove(node)
const node = this._list.tail;
this._list.remove(node);
return node.data
return node.data;
}
[Symbol.iterator] () {
return new DequeIterator(this._list)
[Symbol.iterator]() {
return new DequeIterator(this._list);
}
iterator () {
return new DequeIterator(this._list)
iterator() {
return new DequeIterator(this._list);
}
reverseIterator () {
return new DequeIterator(this._list, true)
reverseIterator() {
return new DequeIterator(this._list, true);
}

@@ -86,8 +86,8 @@

*/
get head () {
get head() {
if (this._list.length === 0) {
return undefined
return undefined;
}
const node = this._list.head
return node.data
const node = this._list.head;
return node.data;
}

@@ -99,15 +99,15 @@

*/
get tail () {
get tail() {
if (this._list.length === 0) {
return undefined
return undefined;
}
const node = this._list.tail
return node.data
const node = this._list.tail;
return node.data;
}
get length () {
return this._list.length
get length() {
return this._list.length;
}
}
module.exports = Deque
module.exports = Deque;

@@ -1,4 +0,4 @@

'use strict'
"use strict";
const DoublyLinkedListIterator = require('./DoublyLinkedListIterator')
const DoublyLinkedListIterator = require("./DoublyLinkedListIterator");
/**

@@ -8,14 +8,14 @@ * Thin wrapper around an underlying DDL iterator

class DequeIterator extends DoublyLinkedListIterator {
next () {
const result = super.next()
next() {
const result = super.next();
// unwrap the node...
if (result.value) {
result.value = result.value.data
result.value = result.value.data;
}
return result
return result;
}
}
module.exports = DequeIterator
module.exports = DequeIterator;

@@ -1,2 +0,2 @@

'use strict'
"use strict";

@@ -18,70 +18,70 @@ /**

class DoublyLinkedList {
constructor () {
this.head = null
this.tail = null
this.length = 0
constructor() {
this.head = null;
this.tail = null;
this.length = 0;
}
insertBeginning (node) {
insertBeginning(node) {
if (this.head === null) {
this.head = node
this.tail = node
node.prev = null
node.next = null
this.length++
this.head = node;
this.tail = node;
node.prev = null;
node.next = null;
this.length++;
} else {
this.insertBefore(this.head, node)
this.insertBefore(this.head, node);
}
}
insertEnd (node) {
insertEnd(node) {
if (this.tail === null) {
this.insertBeginning(node)
this.insertBeginning(node);
} else {
this.insertAfter(this.tail, node)
this.insertAfter(this.tail, node);
}
}
insertAfter (node, newNode) {
newNode.prev = node
newNode.next = node.next
insertAfter(node, newNode) {
newNode.prev = node;
newNode.next = node.next;
if (node.next === null) {
this.tail = newNode
this.tail = newNode;
} else {
node.next.prev = newNode
node.next.prev = newNode;
}
node.next = newNode
this.length++
node.next = newNode;
this.length++;
}
insertBefore (node, newNode) {
newNode.prev = node.prev
newNode.next = node
insertBefore(node, newNode) {
newNode.prev = node.prev;
newNode.next = node;
if (node.prev === null) {
this.head = newNode
this.head = newNode;
} else {
node.prev.next = newNode
node.prev.next = newNode;
}
node.prev = newNode
this.length++
node.prev = newNode;
this.length++;
}
remove (node) {
remove(node) {
if (node.prev === null) {
this.head = node.next
this.head = node.next;
} else {
node.prev.next = node.next
node.prev.next = node.next;
}
if (node.next === null) {
this.tail = node.prev
this.tail = node.prev;
} else {
node.next.prev = node.prev
node.next.prev = node.prev;
}
node.prev = null
node.next = null
this.length--
node.prev = null;
node.next = null;
this.length--;
}
// FIXME: this should not live here and has become a dumping ground...
static createNode (data) {
static createNode(data) {
return {

@@ -91,6 +91,6 @@ prev: null,

data: data
}
};
}
}
module.exports = DoublyLinkedList
module.exports = DoublyLinkedList;

@@ -1,2 +0,2 @@

'use strict'
"use strict";

@@ -17,3 +17,2 @@ /**

class DoublyLinkedListIterator {
/**

@@ -23,45 +22,49 @@ * @param {Object} doublyLinkedListNode a node that is part of a doublyLinkedList

*/
constructor (doublyLinkedList, reverse) {
this._list = doublyLinkedList
constructor(doublyLinkedList, reverse) {
this._list = doublyLinkedList;
// NOTE: these key names are tied to the DoublyLinkedListIterator
this._direction = reverse === true ? 'prev' : 'next'
this._startPosition = reverse === true ? 'tail' : 'head'
this._started = false
this._cursor = null
this._done = false
this._direction = reverse === true ? "prev" : "next";
this._startPosition = reverse === true ? "tail" : "head";
this._started = false;
this._cursor = null;
this._done = false;
}
_start () {
this._cursor = this._list[this._startPosition]
this._started = true
_start() {
this._cursor = this._list[this._startPosition];
this._started = true;
}
_advanceCursor () {
_advanceCursor() {
if (this._started === false) {
this._started = true
this._cursor = this._list[this._startPosition]
return
this._started = true;
this._cursor = this._list[this._startPosition];
return;
}
this._cursor = this._cursor[this._direction]
this._cursor = this._cursor[this._direction];
}
reset () {
this._done = false
this._started = false
this._cursor = null
reset() {
this._done = false;
this._started = false;
this._cursor = null;
}
remove () {
if (this._started === false || this._done === true || this._isCursorDetached()) {
return false
remove() {
if (
this._started === false ||
this._done === true ||
this._isCursorDetached()
) {
return false;
}
this._list.remove(this._cursor)
this._list.remove(this._cursor);
}
next () {
next() {
if (this._done === true) {
return { done: true }
return { done: true };
}
this._advanceCursor()
this._advanceCursor();

@@ -71,4 +74,4 @@ // if there is no node at the cursor or the node at the cursor is no longer part of

if (this._cursor === null || this._isCursorDetached()) {
this._done = true
return { done: true }
this._done = true;
return { done: true };
}

@@ -79,3 +82,3 @@

done: false
}
};
}

@@ -92,7 +95,12 @@

*/
_isCursorDetached () {
return this._cursor.prev === null && this._cursor.next === null && this._list.tail !== this._cursor && this._list.head !== this._cursor
_isCursorDetached() {
return (
this._cursor.prev === null &&
this._cursor.next === null &&
this._list.tail !== this._cursor &&
this._list.head !== this._cursor
);
}
}
module.exports = DoublyLinkedListIterator
module.exports = DoublyLinkedListIterator;

@@ -1,12 +0,12 @@

'use strict'
"use strict";
class ExtendableError extends Error {
constructor (message) {
super(message)
this.name = this.constructor.name
this.message = message
if (typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, this.constructor)
constructor(message) {
super(message);
this.name = this.constructor.name;
this.message = message;
if (typeof Error.captureStackTrace === "function") {
Error.captureStackTrace(this, this.constructor);
} else {
this.stack = (new Error(message)).stack
this.stack = new Error(message).stack;
}

@@ -18,4 +18,4 @@ }

class TimeoutError extends ExtendableError {
constructor (m) {
super(m)
constructor(m) {
super(m);
}

@@ -27,2 +27,2 @@ }

TimeoutError: TimeoutError
}
};

@@ -1,14 +0,16 @@

module.exports = function (factory) {
if (typeof factory.create !== 'function') {
throw new TypeError('factory.create must be a function')
module.exports = function(factory) {
if (typeof factory.create !== "function") {
throw new TypeError("factory.create must be a function");
}
if (typeof factory.destroy !== 'function') {
throw new TypeError('factory.destroy must be a function')
if (typeof factory.destroy !== "function") {
throw new TypeError("factory.destroy must be a function");
}
if (typeof factory.validate !== 'undefined' && typeof factory.validate !== 'function') {
throw new TypeError('factory.validate must be a function')
if (
typeof factory.validate !== "undefined" &&
typeof factory.validate !== "function"
) {
throw new TypeError("factory.validate must be a function");
}
}
};

@@ -1,12 +0,12 @@

'use strict'
"use strict";
const EventEmitter = require('events').EventEmitter
const EventEmitter = require("events").EventEmitter;
const factoryValidator = require('./factoryValidator')
const PoolOptions = require('./PoolOptions')
const ResourceRequest = require('./ResourceRequest')
const ResourceLoan = require('./ResourceLoan')
const PooledResource = require('./PooledResource')
const factoryValidator = require("./factoryValidator");
const PoolOptions = require("./PoolOptions");
const ResourceRequest = require("./ResourceRequest");
const ResourceLoan = require("./ResourceLoan");
const PooledResource = require("./PooledResource");
const reflector = require('./utils').reflector
const reflector = require("./utils").reflector;

@@ -16,7 +16,6 @@ /**

*/
const FACTORY_CREATE_ERROR = 'factoryCreateError'
const FACTORY_DESTROY_ERROR = 'factoryDestroyError'
const FACTORY_CREATE_ERROR = "factoryCreateError";
const FACTORY_DESTROY_ERROR = "factoryDestroyError";
class Pool extends EventEmitter {
/**

@@ -37,15 +36,15 @@ * Generate an Object pool with a specified `factory` and `config`.

*/
constructor (Evictor, Deque, PriorityQueue, factory, options) {
super()
constructor(Evictor, Deque, PriorityQueue, factory, options) {
super();
factoryValidator(factory)
factoryValidator(factory);
this._config = new PoolOptions(options)
this._config = new PoolOptions(options);
// TODO: fix up this ugly glue-ing
this._Promise = this._config.Promise
this._Promise = this._config.Promise;
this._factory = factory
this._draining = false
this._started = false
this._factory = factory;
this._draining = false;
this._started = false;
/**

@@ -55,3 +54,3 @@ * Holds waiting clients

*/
this._waitingClientsQueue = new PriorityQueue(this._config.priorityRange)
this._waitingClientsQueue = new PriorityQueue(this._config.priorityRange);

@@ -62,3 +61,3 @@ /**

*/
this._factoryCreateOperations = new Set()
this._factoryCreateOperations = new Set();

@@ -69,3 +68,3 @@ /**

*/
this._factoryDestroyOperations = new Set()
this._factoryDestroyOperations = new Set();

@@ -77,3 +76,3 @@ /**

*/
this._availableObjects = new Deque()
this._availableObjects = new Deque();

@@ -84,3 +83,3 @@ /**

*/
this._testOnBorrowResources = new Set()
this._testOnBorrowResources = new Set();

@@ -91,3 +90,3 @@ /**

*/
this._testOnReturnResources = new Set()
this._testOnReturnResources = new Set();

@@ -98,3 +97,3 @@ /**

*/
this._validationOperations = new Set()
this._validationOperations = new Set();

@@ -105,3 +104,3 @@ /**

*/
this._allObjects = new Set()
this._allObjects = new Set();

@@ -112,3 +111,3 @@ /**

*/
this._resourceLoans = new Map()
this._resourceLoans = new Map();

@@ -119,5 +118,5 @@ /**

*/
this._evictionIterator = this._availableObjects.iterator()
this._evictionIterator = this._availableObjects.iterator();
this._evictor = new Evictor()
this._evictor = new Evictor();

@@ -128,25 +127,27 @@ /**

*/
this._scheduledEviction = null
this._scheduledEviction = null;
// create initial resources (if factory.min > 0)
if (this._config.autostart === true) {
this.start()
this.start();
}
}
_destroy (pooledResource) {
_destroy(pooledResource) {
// FIXME: do we need another state for "in destruction"?
pooledResource.invalidate()
this._allObjects.delete(pooledResource)
pooledResource.invalidate();
this._allObjects.delete(pooledResource);
// NOTE: this maybe very bad promise usage?
const destroyPromise = this._factory.destroy(pooledResource.obj)
const wrappedDestroyPromise = this._Promise.resolve(destroyPromise)
const destroyPromise = this._factory.destroy(pooledResource.obj);
const wrappedDestroyPromise = this._Promise.resolve(destroyPromise);
this._trackOperation(wrappedDestroyPromise, this._factoryDestroyOperations)
.catch((reason) => {
this.emit(FACTORY_DESTROY_ERROR, reason)
})
this._trackOperation(
wrappedDestroyPromise,
this._factoryDestroyOperations
).catch(reason => {
this.emit(FACTORY_DESTROY_ERROR, reason);
});
// TODO: maybe ensuring minimum pool size should live outside here
this._ensureMinimum()
this._ensureMinimum();
}

@@ -158,28 +159,30 @@

*/
_testOnBorrow () {
_testOnBorrow() {
if (this._availableObjects.length < 1) {
return false
return false;
}
const pooledResource = this._availableObjects.shift()
const pooledResource = this._availableObjects.shift();
// Mark the resource as in test
pooledResource.test()
this._testOnBorrowResources.add(pooledResource)
const validationPromise = this._factory.validate(pooledResource.obj)
const wrappedValidationPromise = this._Promise.resolve(validationPromise)
pooledResource.test();
this._testOnBorrowResources.add(pooledResource);
const validationPromise = this._factory.validate(pooledResource.obj);
const wrappedValidationPromise = this._Promise.resolve(validationPromise);
this._trackOperation(wrappedValidationPromise, this._validationOperations)
.then((isValid) => {
this._testOnBorrowResources.delete(pooledResource)
this._trackOperation(
wrappedValidationPromise,
this._validationOperations
).then(isValid => {
this._testOnBorrowResources.delete(pooledResource);
if (isValid === false) {
pooledResource.invalidate()
this._destroy(pooledResource)
this._dispense()
return
pooledResource.invalidate();
this._destroy(pooledResource);
this._dispense();
return;
}
this._dispatchPooledResourceToNextWaitingClient(pooledResource)
})
this._dispatchPooledResourceToNextWaitingClient(pooledResource);
});
return true
return true;
}

@@ -191,10 +194,10 @@

*/
_dispatchResource () {
_dispatchResource() {
if (this._availableObjects.length < 1) {
return false
return false;
}
const pooledResource = this._availableObjects.shift()
this._dispatchPooledResourceToNextWaitingClient(pooledResource)
return
const pooledResource = this._availableObjects.shift();
this._dispatchPooledResourceToNextWaitingClient(pooledResource);
return;
}

@@ -208,3 +211,3 @@

*/
_dispense () {
_dispense() {
/**

@@ -214,3 +217,3 @@ * Local variables for ease of reading/writing

*/
const numWaitingClients = this._waitingClientsQueue.length
const numWaitingClients = this._waitingClientsQueue.length;

@@ -220,10 +223,14 @@ // If there aren't any waiting requests then there is nothing to do

if (numWaitingClients < 1) {
return
return;
}
const resourceShortfall = numWaitingClients - this._potentiallyAllocableResourceCount
const resourceShortfall =
numWaitingClients - this._potentiallyAllocableResourceCount;
const actualNumberOfResourcesToCreate = Math.min(this.spareResourceCapacity, resourceShortfall)
const actualNumberOfResourcesToCreate = Math.min(
this.spareResourceCapacity,
resourceShortfall
);
for (let i = 0; actualNumberOfResourcesToCreate > i; i++) {
this._createResource()
this._createResource();
}

@@ -235,6 +242,10 @@

// how many available resources do we need to shift into test
const desiredNumberOfResourcesToMoveIntoTest = numWaitingClients - this._testOnBorrowResources.size
const actualNumberOfResourcesToMoveIntoTest = Math.min(this._availableObjects.length, desiredNumberOfResourcesToMoveIntoTest)
const desiredNumberOfResourcesToMoveIntoTest =
numWaitingClients - this._testOnBorrowResources.size;
const actualNumberOfResourcesToMoveIntoTest = Math.min(
this._availableObjects.length,
desiredNumberOfResourcesToMoveIntoTest
);
for (let i = 0; actualNumberOfResourcesToMoveIntoTest > i; i++) {
this._testOnBorrow()
this._testOnBorrow();
}

@@ -245,5 +256,8 @@ }

if (this._config.testOnBorrow === false) {
const actualNumberOfResourcesToDispatch = Math.min(this._availableObjects.length, numWaitingClients)
const actualNumberOfResourcesToDispatch = Math.min(
this._availableObjects.length,
numWaitingClients
);
for (let i = 0; actualNumberOfResourcesToDispatch > i; i++) {
this._dispatchResource()
this._dispatchResource();
}

@@ -259,16 +273,16 @@ }

*/
_dispatchPooledResourceToNextWaitingClient (pooledResource) {
const clientResourceRequest = this._waitingClientsQueue.dequeue()
_dispatchPooledResourceToNextWaitingClient(pooledResource) {
const clientResourceRequest = this._waitingClientsQueue.dequeue();
if (clientResourceRequest === undefined) {
// While we were away either all the waiting clients timed out
// or were somehow fulfilled. put our pooledResource back.
this._addPooledResourceToAvailableObjects(pooledResource)
this._addPooledResourceToAvailableObjects(pooledResource);
// TODO: do need to trigger anything before we leave?
return false
return false;
}
const loan = new ResourceLoan(pooledResource, this._Promise)
this._resourceLoans.set(pooledResource.obj, loan)
pooledResource.allocate()
clientResourceRequest.resolve(pooledResource.obj)
return true
const loan = new ResourceLoan(pooledResource, this._Promise);
this._resourceLoans.set(pooledResource.obj, loan);
pooledResource.allocate();
clientResourceRequest.resolve(pooledResource.obj);
return true;
}

@@ -283,12 +297,15 @@

*/
_trackOperation (operation, set) {
set.add(operation)
_trackOperation(operation, set) {
set.add(operation);
return operation.then((v) => {
set.delete(operation)
return this._Promise.resolve(v)
}, (e) => {
set.delete(operation)
return this._Promise.reject(e)
})
return operation.then(
v => {
set.delete(operation);
return this._Promise.resolve(v);
},
e => {
set.delete(operation);
return this._Promise.reject(e);
}
);
}

@@ -299,23 +316,23 @@

*/
_createResource () {
_createResource() {
// An attempt to create a resource
const factoryPromise = this._factory.create()
const wrappedFactoryPromise = this._Promise.resolve(factoryPromise)
const factoryPromise = this._factory.create();
const wrappedFactoryPromise = this._Promise.resolve(factoryPromise);
this._trackOperation(wrappedFactoryPromise, this._factoryCreateOperations)
.then((resource) => {
this._handleNewResource(resource)
return null
})
.catch((reason) => {
this.emit(FACTORY_CREATE_ERROR, reason)
this._dispense()
})
.then(resource => {
this._handleNewResource(resource);
return null;
})
.catch(reason => {
this.emit(FACTORY_CREATE_ERROR, reason);
this._dispense();
});
}
_handleNewResource (resource) {
const pooledResource = new PooledResource(resource)
this._allObjects.add(pooledResource)
_handleNewResource(resource) {
const pooledResource = new PooledResource(resource);
this._allObjects.add(pooledResource);
// TODO: check we aren't exceding our maxPoolSize before doing
this._dispatchPooledResourceToNextWaitingClient(pooledResource)
this._dispatchPooledResourceToNextWaitingClient(pooledResource);
}

@@ -326,14 +343,17 @@

*/
_ensureMinimum () {
_ensureMinimum() {
if (this._draining === true) {
return
return;
}
const minShortfall = this._config.min - this._count
const minShortfall = this._config.min - this._count;
for (let i = 0; i < minShortfall; i++) {
this._createResource()
this._createResource();
}
}
_evict () {
const testsToRun = Math.min(this._config.numTestsPerEvictionRun, this._availableObjects.length)
_evict() {
const testsToRun = Math.min(
this._config.numTestsPerEvictionRun,
this._availableObjects.length
);
const evictionConfig = {

@@ -343,5 +363,5 @@ softIdleTimeoutMillis: this._config.softIdleTimeoutMillis,

min: this._config.min
}
for (let testsHaveRun = 0; testsHaveRun < testsToRun;) {
const iterationResult = this._evictionIterator.next()
};
for (let testsHaveRun = 0; testsHaveRun < testsToRun; ) {
const iterationResult = this._evictionIterator.next();

@@ -351,4 +371,4 @@ // Safety check incase we could get stuck in infinite loop because we

if (iterationResult.done === true && this._availableObjects.length < 1) {
this._evictionIterator.reset()
return
this._evictionIterator.reset();
return;
}

@@ -358,15 +378,19 @@ // if this happens it should just mean we reached the end of the

if (iterationResult.done === true && this._availableObjects.length > 0) {
this._evictionIterator.reset()
break
this._evictionIterator.reset();
break;
}
const resource = iterationResult.value
const resource = iterationResult.value;
const shouldEvict = this._evictor.evict(evictionConfig, resource, this._availableObjects.length)
testsHaveRun++
const shouldEvict = this._evictor.evict(
evictionConfig,
resource,
this._availableObjects.length
);
testsHaveRun++;
if (shouldEvict === true) {
// take it out of the _availableObjects list
this._evictionIterator.remove()
this._destroy(resource)
this._evictionIterator.remove();
this._destroy(resource);
}

@@ -376,27 +400,27 @@ }

_scheduleEvictorRun () {
_scheduleEvictorRun() {
// Start eviction if set
if (this._config.evictionRunIntervalMillis > 0) {
this._scheduledEviction = setTimeout(() => {
this._evict()
this._scheduleEvictorRun()
}, this._config.evictionRunIntervalMillis)
this._evict();
this._scheduleEvictorRun();
}, this._config.evictionRunIntervalMillis);
}
}
_descheduleEvictorRun () {
clearTimeout(this._scheduledEviction)
this._scheduledEviction = null
_descheduleEvictorRun() {
clearTimeout(this._scheduledEviction);
this._scheduledEviction = null;
}
start () {
start() {
if (this._draining === true) {
return
return;
}
if (this._started === true) {
return
return;
}
this._started = true
this._scheduleEvictorRun()
this._ensureMinimum()
this._started = true;
this._scheduleEvictorRun();
this._ensureMinimum();
}

@@ -422,37 +446,67 @@

*/
acquire (priority) {
acquire(priority) {
if (this._started === false && this._config.autostart === false) {
this.start()
this.start();
}
if (this._draining) {
return this._Promise.reject(new Error('pool is draining and cannot accept work'))
return this._Promise.reject(
new Error("pool is draining and cannot accept work")
);
}
// TODO: should we defer this check till after this event loop incase "the situation" changes in the meantime
if (this._config.maxWaitingClients !== undefined && this._waitingClientsQueue.length >= this._config.maxWaitingClients) {
return this._Promise.reject(new Error('max waitingClients count exceeded'))
if (
this._config.maxWaitingClients !== undefined &&
this._waitingClientsQueue.length >= this._config.maxWaitingClients
) {
return this._Promise.reject(
new Error("max waitingClients count exceeded")
);
}
const resourceRequest = new ResourceRequest(this._config.acquireTimeoutMillis, this._Promise)
this._waitingClientsQueue.enqueue(resourceRequest, priority)
this._dispense()
const resourceRequest = new ResourceRequest(
this._config.acquireTimeoutMillis,
this._Promise
);
this._waitingClientsQueue.enqueue(resourceRequest, priority);
this._dispense();
return resourceRequest.promise
return resourceRequest.promise;
}
/**
* Check if resource is currently on loan from the pool
*
* @param {Function} resource
* Resource for checking.
*
* @returns {Boolean}
* True if resource belongs to this pool and false otherwise
*/
isBorrowedResource (resource) {
return this._resourceLoans.get(resource) !== undefined
/**
* [use method, aquires a resource, passes the resource to a user supplied function and releases it]
* @param {Function} fn [a function that accepts a resource and returns a promise that resolves/rejects once it has finished using the resource]
* @return {Promise} [resolves once the resource is released to the pool]
*/
use(fn) {
return this.acquire().then(resource => {
fn(resource).then(
result => {
this.release(resource);
return result;
},
err => {
this.release(resource);
throw err;
}
);
});
}
/**
* Check if resource is currently on loan from the pool
*
* @param {Function} resource
* Resource for checking.
*
* @returns {Boolean}
* True if resource belongs to this pool and false otherwise
*/
isBorrowedResource(resource) {
return this._resourceLoans.get(resource) !== undefined;
}
/**
* Return the resource to the pool when it is no longer required.

@@ -463,19 +517,21 @@ *

*/
release (resource) {
release(resource) {
// check for an outstanding loan
const loan = this._resourceLoans.get(resource)
const loan = this._resourceLoans.get(resource);
if (loan === undefined) {
return this._Promise.reject(new Error('Resource not currently part of this pool'))
return this._Promise.reject(
new Error("Resource not currently part of this pool")
);
}
this._resourceLoans.delete(resource)
loan.resolve()
const pooledResource = loan.pooledResource
this._resourceLoans.delete(resource);
loan.resolve();
const pooledResource = loan.pooledResource;
pooledResource.deallocate()
this._addPooledResourceToAvailableObjects(pooledResource)
pooledResource.deallocate();
this._addPooledResourceToAvailableObjects(pooledResource);
this._dispense()
return this._Promise.resolve()
this._dispense();
return this._Promise.resolve();
}

@@ -492,27 +548,29 @@

*/
destroy (resource) {
destroy(resource) {
// check for an outstanding loan
const loan = this._resourceLoans.get(resource)
const loan = this._resourceLoans.get(resource);
if (loan === undefined) {
return this._Promise.reject(new Error('Resource not currently part of this pool'))
return this._Promise.reject(
new Error("Resource not currently part of this pool")
);
}
this._resourceLoans.delete(resource)
loan.resolve()
const pooledResource = loan.pooledResource
this._resourceLoans.delete(resource);
loan.resolve();
const pooledResource = loan.pooledResource;
pooledResource.deallocate()
this._destroy(pooledResource)
pooledResource.deallocate();
this._destroy(pooledResource);
this._dispense()
return this._Promise.resolve()
this._dispense();
return this._Promise.resolve();
}
_addPooledResourceToAvailableObjects (pooledResource) {
pooledResource.idle()
_addPooledResourceToAvailableObjects(pooledResource) {
pooledResource.idle();
if (this._config.fifo === true) {
this._availableObjects.push(pooledResource)
this._availableObjects.push(pooledResource);
} else {
this._availableObjects.unshift(pooledResource)
this._availableObjects.unshift(pooledResource);
}

@@ -529,28 +587,28 @@ }

*/
drain () {
this._draining = true
drain() {
this._draining = true;
return this.__allResourceRequestsSettled()
.then(() => {
return this.__allResourcesReturned()
return this.__allResourcesReturned();
})
.then(() => {
this._descheduleEvictorRun()
})
this._descheduleEvictorRun();
});
}
__allResourceRequestsSettled () {
__allResourceRequestsSettled() {
if (this._waitingClientsQueue.length > 0) {
// wait for last waiting client to be settled
// FIXME: what if they can "resolve" out of order....?
return reflector(this._waitingClientsQueue.tail.promise)
return reflector(this._waitingClientsQueue.tail.promise);
}
return this._Promise.resolve()
return this._Promise.resolve();
}
// FIXME: this is a horrific mess
__allResourcesReturned () {
__allResourcesReturned() {
const ps = Array.from(this._resourceLoans.values())
.map((loan) => loan.promise)
.map(reflector)
return this._Promise.all(ps)
.map(loan => loan.promise)
.map(reflector);
return this._Promise.all(ps);
}

@@ -569,17 +627,18 @@

*/
clear () {
const reflectedCreatePromises = Array.from(this._factoryCreateOperations)
.map(reflector)
clear() {
const reflectedCreatePromises = Array.from(
this._factoryCreateOperations
).map(reflector);
// wait for outstanding factory.create to complete
return this._Promise.all(reflectedCreatePromises)
.then(() => {
return this._Promise.all(reflectedCreatePromises).then(() => {
// Destroy existing resources
for (const resource of this._availableObjects) {
this._destroy(resource)
this._destroy(resource);
}
const reflectedDestroyPromises = Array.from(this._factoryDestroyOperations)
.map(reflector)
return this._Promise.all(reflectedDestroyPromises)
})
const reflectedDestroyPromises = Array.from(
this._factoryDestroyOperations
).map(reflector);
return this._Promise.all(reflectedDestroyPromises);
});
}

@@ -593,7 +652,9 @@

*/
get _potentiallyAllocableResourceCount () {
return this._availableObjects.length +
get _potentiallyAllocableResourceCount() {
return (
this._availableObjects.length +
this._testOnBorrowResources.size +
this._testOnReturnResources.size +
this._factoryCreateOperations.size
);
}

@@ -608,4 +669,4 @@

*/
get _count () {
return this._allObjects.size + this._factoryCreateOperations.size
get _count() {
return this._allObjects.size + this._factoryCreateOperations.size;
}

@@ -617,4 +678,7 @@

*/
get spareResourceCapacity () {
return this._config.max - (this._allObjects.size + this._factoryCreateOperations.size)
get spareResourceCapacity() {
return (
this._config.max -
(this._allObjects.size + this._factoryCreateOperations.size)
);
}

@@ -626,4 +690,4 @@

*/
get size () {
return this._count
get size() {
return this._count;
}

@@ -635,4 +699,4 @@

*/
get available () {
return this._availableObjects.length
get available() {
return this._availableObjects.length;
}

@@ -644,4 +708,4 @@

*/
get borrowed () {
return this._resourceLoans.size
get borrowed() {
return this._resourceLoans.size;
}

@@ -653,4 +717,4 @@

*/
get pending () {
return this._waitingClientsQueue.length
get pending() {
return this._waitingClientsQueue.length;
}

@@ -662,4 +726,4 @@

*/
get max () {
return this._config.max
get max() {
return this._config.max;
}

@@ -671,7 +735,7 @@

*/
get min () {
return this._config.min
get min() {
return this._config.min;
}
}
module.exports = Pool
module.exports = Pool;

@@ -1,2 +0,2 @@

'use strict'
"use strict";
/**

@@ -8,27 +8,27 @@ * Create the default settings used by the pool

class PoolDefaults {
constructor () {
this.fifo = true
this.priorityRange = 1
constructor() {
this.fifo = true;
this.priorityRange = 1;
this.testOnBorrow = false
this.testOnReturn = false
this.testOnBorrow = false;
this.testOnReturn = false;
this.autostart = true
this.autostart = true;
this.evictionRunIntervalMillis = 0
this.numTestsPerEvictionRun = 3
this.softIdleTimeoutMillis = -1
this.idleTimeoutMillis = 30000
this.evictionRunIntervalMillis = 0;
this.numTestsPerEvictionRun = 3;
this.softIdleTimeoutMillis = -1;
this.idleTimeoutMillis = 30000;
// FIXME: no defaults!
this.acquireTimeoutMillis = null
this.maxWaitingClients = null
this.acquireTimeoutMillis = null;
this.maxWaitingClients = null;
this.min = null
this.max = null
this.min = null;
this.max = null;
// FIXME: this seems odd?
this.Promise = Promise
this.Promise = Promise;
}
}
module.exports = PoolDefaults
module.exports = PoolDefaults;

@@ -1,4 +0,4 @@

'use strict'
"use strict";
const PooledResourceStateEnum = require('./PooledResourceStateEnum')
const PooledResourceStateEnum = require("./PooledResourceStateEnum");

@@ -10,41 +10,41 @@ /**

class PooledResource {
constructor (resource) {
this.creationTime = Date.now()
this.lastReturnTime = null
this.lastBorrowTime = null
this.lastIdleTime = null
this.obj = resource
this.state = PooledResourceStateEnum.IDLE
constructor(resource) {
this.creationTime = Date.now();
this.lastReturnTime = null;
this.lastBorrowTime = null;
this.lastIdleTime = null;
this.obj = resource;
this.state = PooledResourceStateEnum.IDLE;
}
// mark the resource as "allocated"
allocate () {
this.lastBorrowTime = Date.now()
this.state = PooledResourceStateEnum.ALLOCATED
allocate() {
this.lastBorrowTime = Date.now();
this.state = PooledResourceStateEnum.ALLOCATED;
}
// mark the resource as "deallocated"
deallocate () {
this.lastReturnTime = Date.now()
this.state = PooledResourceStateEnum.IDLE
deallocate() {
this.lastReturnTime = Date.now();
this.state = PooledResourceStateEnum.IDLE;
}
invalidate () {
this.state = PooledResourceStateEnum.INVALID
invalidate() {
this.state = PooledResourceStateEnum.INVALID;
}
test () {
this.state = PooledResourceStateEnum.VALIDATION
test() {
this.state = PooledResourceStateEnum.VALIDATION;
}
idle () {
this.lastIdleTime = Date.now()
this.state = PooledResourceStateEnum.IDLE
idle() {
this.lastIdleTime = Date.now();
this.state = PooledResourceStateEnum.IDLE;
}
returning () {
this.state = PooledResourceStateEnum.RETURNING
returning() {
this.state = PooledResourceStateEnum.RETURNING;
}
}
module.exports = PooledResource
module.exports = PooledResource;

@@ -1,11 +0,11 @@

'use strict'
"use strict";
const PooledResourceStateEnum = {
ALLOCATED: 'ALLOCATED', // In use
IDLE: 'IDLE', // In the queue, not in use.
INVALID: 'INVALID', // Failed validation
RETURNING: 'RETURNING', // Resource is in process of returning
VALIDATION: 'VALIDATION' // Currently being tested
}
ALLOCATED: "ALLOCATED", // In use
IDLE: "IDLE", // In the queue, not in use.
INVALID: "INVALID", // Failed validation
RETURNING: "RETURNING", // Resource is in process of returning
VALIDATION: "VALIDATION" // Currently being tested
};
module.exports = PooledResourceStateEnum
module.exports = PooledResourceStateEnum;

@@ -1,4 +0,4 @@

'use strict'
"use strict";
const PoolDefaults = require('./PoolDefaults')
const PoolDefaults = require("./PoolDefaults");

@@ -43,38 +43,51 @@ class PoolOptions {

*/
constructor (opts) {
const poolDefaults = new PoolDefaults()
constructor(opts) {
const poolDefaults = new PoolDefaults();
opts = opts || {}
opts = opts || {};
this.fifo = (typeof opts.fifo === 'boolean') ? opts.fifo : poolDefaults.fifo
this.priorityRange = opts.priorityRange || poolDefaults.priorityRange
this.fifo = typeof opts.fifo === "boolean" ? opts.fifo : poolDefaults.fifo;
this.priorityRange = opts.priorityRange || poolDefaults.priorityRange;
this.testOnBorrow = (typeof opts.testOnBorrow === 'boolean') ? opts.testOnBorrow : poolDefaults.testOnBorrow
this.testOnReturn = (typeof opts.testOnReturn === 'boolean') ? opts.testOnReturn : poolDefaults.testOnReturn
this.testOnBorrow =
typeof opts.testOnBorrow === "boolean"
? opts.testOnBorrow
: poolDefaults.testOnBorrow;
this.testOnReturn =
typeof opts.testOnReturn === "boolean"
? opts.testOnReturn
: poolDefaults.testOnReturn;
this.autostart = (typeof opts.autostart === 'boolean') ? opts.autostart : poolDefaults.autostart
this.autostart =
typeof opts.autostart === "boolean"
? opts.autostart
: poolDefaults.autostart;
if (opts.acquireTimeoutMillis) {
this.acquireTimeoutMillis = parseInt(opts.acquireTimeoutMillis, 10)
this.acquireTimeoutMillis = parseInt(opts.acquireTimeoutMillis, 10);
}
if (opts.maxWaitingClients) {
this.maxWaitingClients = parseInt(opts.maxWaitingClients, 10)
this.maxWaitingClients = parseInt(opts.maxWaitingClients, 10);
}
this.max = parseInt(opts.max, 10)
this.min = parseInt(opts.min, 10)
this.max = parseInt(opts.max, 10);
this.min = parseInt(opts.min, 10);
this.max = Math.max(isNaN(this.max) ? 1 : this.max, 1)
this.min = Math.min(isNaN(this.min) ? 0 : this.min, this.max)
this.max = Math.max(isNaN(this.max) ? 1 : this.max, 1);
this.min = Math.min(isNaN(this.min) ? 0 : this.min, this.max);
this.evictionRunIntervalMillis = opts.evictionRunIntervalMillis || poolDefaults.evictionRunIntervalMillis
this.numTestsPerEvictionRun = opts.numTestsPerEvictionRun || poolDefaults.numTestsPerEvictionRun
this.softIdleTimeoutMillis = opts.softIdleTimeoutMillis || poolDefaults.softIdleTimeoutMillis
this.idleTimeoutMillis = opts.idleTimeoutMillis || poolDefaults.idleTimeoutMillis
this.evictionRunIntervalMillis =
opts.evictionRunIntervalMillis || poolDefaults.evictionRunIntervalMillis;
this.numTestsPerEvictionRun =
opts.numTestsPerEvictionRun || poolDefaults.numTestsPerEvictionRun;
this.softIdleTimeoutMillis =
opts.softIdleTimeoutMillis || poolDefaults.softIdleTimeoutMillis;
this.idleTimeoutMillis =
opts.idleTimeoutMillis || poolDefaults.idleTimeoutMillis;
this.Promise = (opts.Promise != null) ? opts.Promise : poolDefaults.Promise
this.Promise = opts.Promise != null ? opts.Promise : poolDefaults.Promise;
}
}
module.exports = PoolOptions
module.exports = PoolOptions;

@@ -1,4 +0,4 @@

'use strict'
"use strict";
const Queue = require('./Queue')
const Queue = require("./Queue");

@@ -10,60 +10,60 @@ /**

class PriorityQueue {
constructor (size) {
this._size = Math.max(+size | 0, 1)
this._slots = []
constructor(size) {
this._size = Math.max(+size | 0, 1);
this._slots = [];
// initialize arrays to hold queue elements
for (let i = 0; i < this._size; i++) {
this._slots.push(new Queue())
this._slots.push(new Queue());
}
}
get length () {
let _length = 0
get length() {
let _length = 0;
for (let i = 0, slots = this._slots.length; i < slots; i++) {
_length += this._slots[i].length
_length += this._slots[i].length;
}
return _length
return _length;
}
enqueue (obj, priority) {
enqueue(obj, priority) {
// Convert to integer with a default value of 0.
priority = priority && +priority | 0 || 0
priority = (priority && +priority | 0) || 0;
if (priority) {
if (priority < 0 || priority >= this._size) {
priority = (this._size - 1)
priority = this._size - 1;
// put obj at the end of the line
}
}
this._slots[priority].push(obj)
this._slots[priority].push(obj);
}
dequeue () {
dequeue() {
for (let i = 0, sl = this._slots.length; i < sl; i += 1) {
if (this._slots[i].length) {
return this._slots[i].shift()
return this._slots[i].shift();
}
}
return
return;
}
get head () {
get head() {
for (let i = 0, sl = this._slots.length; i < sl; i += 1) {
if (this._slots[i].length > 0) {
return this._slots[i].head
return this._slots[i].head;
}
}
return
return;
}
get tail () {
get tail() {
for (let i = this._slots.length - 1; i >= 0; i--) {
if (this._slots[i].length > 0) {
return this._slots[i].tail
return this._slots[i].tail;
}
}
return
return;
}
}
module.exports = PriorityQueue
module.exports = PriorityQueue;

@@ -1,5 +0,5 @@

'use strict'
"use strict";
const DoublyLinkedList = require('./DoublyLinkedList')
const Deque = require('./Deque')
const DoublyLinkedList = require("./DoublyLinkedList");
const Deque = require("./Deque");

@@ -20,17 +20,17 @@ /**

*/
push (resourceRequest) {
const node = DoublyLinkedList.createNode(resourceRequest)
resourceRequest.promise.catch(this._createTimeoutRejectionHandler(node))
this._list.insertEnd(node)
push(resourceRequest) {
const node = DoublyLinkedList.createNode(resourceRequest);
resourceRequest.promise.catch(this._createTimeoutRejectionHandler(node));
this._list.insertEnd(node);
}
_createTimeoutRejectionHandler (node) {
return (reason) => {
if (reason.name === 'TimeoutError') {
this._list.remove(node)
_createTimeoutRejectionHandler(node) {
return reason => {
if (reason.name === "TimeoutError") {
this._list.remove(node);
}
}
};
}
}
module.exports = Queue
module.exports = Queue;

@@ -1,4 +0,4 @@

'use strict'
"use strict";
const Deferred = require('./Deferred')
const Deferred = require("./Deferred");

@@ -16,9 +16,9 @@ /**

*/
constructor (pooledResource, Promise) {
super(Promise)
this._creationTimestamp = Date.now()
this.pooledResource = pooledResource
constructor(pooledResource, Promise) {
super(Promise);
this._creationTimestamp = Date.now();
this.pooledResource = pooledResource;
}
reject () {
reject() {
/**

@@ -30,2 +30,2 @@ * Loans can only be resolved at the moment

module.exports = ResourceLoan
module.exports = ResourceLoan;

@@ -1,10 +0,10 @@

'use strict'
"use strict";
const Deferred = require('./Deferred')
const errors = require('./errors')
const Deferred = require("./Deferred");
const errors = require("./errors");
function fbind (fn, ctx) {
return function bound () {
return fn.apply(ctx, arguments)
}
function fbind(fn, ctx) {
return function bound() {
return fn.apply(ctx, arguments);
};
}

@@ -18,3 +18,2 @@

class ResourceRequest extends Deferred {
/**

@@ -24,51 +23,54 @@ * [constructor description]

*/
constructor (ttl, Promise) {
super(Promise)
this._creationTimestamp = Date.now()
this._timeout = null
constructor(ttl, Promise) {
super(Promise);
this._creationTimestamp = Date.now();
this._timeout = null;
if (ttl !== undefined) {
this.setTimeout(ttl)
this.setTimeout(ttl);
}
}
setTimeout (delay) {
setTimeout(delay) {
if (this._state !== ResourceRequest.PENDING) {
return
return;
}
const ttl = parseInt(delay, 10)
const ttl = parseInt(delay, 10);
if (isNaN(ttl) || ttl <= 0) {
throw new Error('delay must be a positive int')
throw new Error("delay must be a positive int");
}
const age = Date.now() - this._creationTimestamp
const age = Date.now() - this._creationTimestamp;
if (this._timeout) {
this.removeTimeout()
this.removeTimeout();
}
this._timeout = setTimeout(fbind(this._fireTimeout, this), Math.max(ttl - age, 0))
this._timeout = setTimeout(
fbind(this._fireTimeout, this),
Math.max(ttl - age, 0)
);
}
removeTimeout () {
clearTimeout(this._timeout)
this._timeout = null
removeTimeout() {
clearTimeout(this._timeout);
this._timeout = null;
}
_fireTimeout () {
this.reject(new errors.TimeoutError('ResourceRequest timed out'))
_fireTimeout() {
this.reject(new errors.TimeoutError("ResourceRequest timed out"));
}
reject (reason) {
this.removeTimeout()
super.reject(reason)
reject(reason) {
this.removeTimeout();
super.reject(reason);
}
resolve (value) {
this.removeTimeout()
super.resolve(value)
resolve(value) {
this.removeTimeout();
super.resolve(value);
}
}
module.exports = ResourceRequest
module.exports = ResourceRequest;

@@ -1,4 +0,4 @@

'use strict'
"use strict";
function noop () {}
function noop() {}

@@ -11,4 +11,4 @@ /**

*/
exports.reflector = function (promise) {
return promise.then(noop, noop)
}
exports.reflector = function(promise) {
return promise.then(noop, noop);
};
{
"name": "generic-pool",
"description": "Generic resource pooling for Node.JS",
"version": "3.2.0",
"version": "3.3.0",
"author": "James Cooper <james@bitmechanic.com>",

@@ -67,6 +67,7 @@ "contributors": [

"devDependencies": {
"eslint": "^3.4.0",
"eslint-config-standard": "^6.0.0",
"eslint": "^4.9.0",
"eslint-config-prettier": "^2.6.0",
"eslint-plugin-prettier": "^2.3.1",
"eslint-plugin-promise": "^3.3.0",
"eslint-plugin-standard": "^2.0.0",
"prettier": "^1.7.4",
"tap": "^8.0.0"

@@ -78,4 +79,4 @@ },

"scripts": {
"lint": "eslint lib test",
"lint-fix": "eslint --fix lib test",
"lint": "eslint lib test index.js .eslintrc.js",
"lint-fix": "eslint --fix lib test index.js .eslintrc.js",
"test": "tap test/*-test.js "

@@ -82,0 +83,0 @@ },

@@ -13,3 +13,3 @@ [![build status](https://secure.travis-ci.org/coopernurse/node-pool.png)](http://travis-ci.org/coopernurse/node-pool)

Version 3 contains many breaking changes. The differences are mostly minor and I hope easy to accomodate. There is a very rough and basic [upgrade guide](https://gist.github.com/sandfox/5ca20648b60a0cb959638c0cd6fcd02d) I've written, improvements and other attempts most welcome.
Version 3 contains many breaking changes. The differences are mostly minor and I hope easy to accommodate. There is a very rough and basic [upgrade guide](https://gist.github.com/sandfox/5ca20648b60a0cb959638c0cd6fcd02d) I've written, improvements and other attempts most welcome.

@@ -36,4 +36,4 @@ If you are after the older version 2 of this library you should look at the [current github branch](https://github.com/coopernurse/node-pool/tree/v2.5) for it.

```js
var genericPool = require('generic-pool');
var DbDriver = require('some-db-driver');
const genericPool = require("generic-pool");
const DbDriver = require("some-db-driver");

@@ -44,26 +44,16 @@ /**

const factory = {
create: function(){
return new Promise(function(resolve, reject){
var client = DbDriver.createClient()
client.on('connected', function(){
resolve(client)
})
})
},
destroy: function(client){
return new Promise(function(resolve){
client.on('end', function(){
resolve()
})
client.disconnect()
})
}
}
create: function() {
return DbDriver.createClient();
},
destroy: function(client) {
client.disconnect();
}
};
var opts = {
max: 10, // maximum size of the pool
min: 2 // minimum size of the pool
}
const opts = {
max: 10, // maximum size of the pool
min: 2 // minimum size of the pool
};
var myPool = genericPool.createPool(factory, opts)
const myPool = genericPool.createPool(factory, opts);

@@ -76,14 +66,15 @@ /**

// once a resource becomes available
const resourcePromise = myPool.acquire()
const resourcePromise = myPool.acquire();
resourcePromise.then(function(client) {
client.query("select * from foo", [], function() {
// return object back to pool
myPool.release(client);
});
})
.catch(function(err){
// handle error - this is generally a timeout or maxWaitingClients
// error
});
resourcePromise
.then(function(client) {
client.query("select * from foo", [], function() {
// return object back to pool
myPool.release(client);
});
})
.catch(function(err) {
// handle error - this is generally a timeout or maxWaitingClients
// error
});

@@ -96,3 +87,3 @@ /**

myPool.drain().then(function() {
myPool.clear();
myPool.clear();
});

@@ -133,3 +124,3 @@

- `validate`: a function that the pool will call if it wants to validate a resource. It should accept one argument `resource` where `resource` is whatever `factory.create` made. Should return a `Promise` that resolves a `boolean` where `true` indicates the resource is still valid or `false` if the resource is invalid.
- `validate`: a function that the pool will call if it wants to validate a resource. It should accept one argument `resource` where `resource` is whatever `factory.create` made. Should return a `Promise` that resolves a `boolean` where `true` indicates the resource is still valid or `false` if the resource is invalid.

@@ -140,3 +131,3 @@ _Note: The values returned from `create`, `destroy`, and `validate` are all wrapped in a `Promise.resolve` by the pool before being used internally._

An optional object/dictionary with the any of the following properties:
An optional object/dictionary with the any of the following properties:

@@ -207,3 +198,3 @@ - `max`: maximum number of resources to create at any given time. (default=1)

and returns true (primitive, not Promise) if resource is currently borrowed from the pool, false otherwise.
and returns true (primitive, not Promise) if resource is currently borrowed from the pool, false otherwise.

@@ -239,3 +230,3 @@ ### pool.destroy

- `factoryCreateError` : emitted when a promise returned by `factory.create` is rejected. If this event has no listeners then the `error` will be silently discarded
- `error`: whatever `reason` the promise was rejected with.
- `error`: whatever `reason` the promise was rejected with.

@@ -265,3 +256,3 @@ - `factoryDestroyError` : emitted when a promise returned by `factory.destroy` is rejected. If this event has no listeners then the `error` will be silently discarded

Specifying a `priority` to `acquire` that is outside the `priorityRange` set at `Pool` creation time will result in the `priority` being converted the lowest possible `priority`
Specifying a `priority` to `acquire` that is outside the `priorityRange` set at `Pool` creation time will result in the `priority` being converted the lowest possible `priority`

@@ -369,3 +360,3 @@ ```js

We use eslint and the `standard` ruleset.
We use eslint combined with prettier

@@ -372,0 +363,0 @@

@@ -1,139 +0,144 @@

const tap = require('tap')
const DLL = require('../lib/DoublyLinkedList')
const Iterator = require('../lib/DoublyLinkedListIterator')
const tap = require("tap");
const DLL = require("../lib/DoublyLinkedList");
const Iterator = require("../lib/DoublyLinkedListIterator");
tap.test('iterates forward', function (t) {
const dll = new DLL()
tap.test("iterates forward", function(t) {
const dll = new DLL();
const node1 = DLL.createNode({id: 1})
const node2 = DLL.createNode({id: 2})
const node3 = DLL.createNode({id: 3})
const node4 = DLL.createNode({id: 4})
const node1 = DLL.createNode({ id: 1 });
const node2 = DLL.createNode({ id: 2 });
const node3 = DLL.createNode({ id: 3 });
const node4 = DLL.createNode({ id: 4 });
dll.insertBeginning(node1)
dll.insertBeginning(node2)
dll.insertBeginning(node3)
dll.insertBeginning(node4)
dll.insertBeginning(node1);
dll.insertBeginning(node2);
dll.insertBeginning(node3);
dll.insertBeginning(node4);
const iterator = new Iterator(dll)
const iterator = new Iterator(dll);
const iterationResult1 = iterator.next()
t.notOk(iterationResult1.done)
t.same(iterationResult1.value, node4)
const iterationResult1 = iterator.next();
t.notOk(iterationResult1.done);
t.same(iterationResult1.value, node4);
iterator.next()
iterator.next()
iterator.next();
iterator.next();
const iterationResult4 = iterator.next()
t.notOk(iterationResult4.done)
t.same(iterationResult4.value, node1)
const iterationResult4 = iterator.next();
t.notOk(iterationResult4.done);
t.same(iterationResult4.value, node1);
const iterationResult5 = iterator.next()
t.ok(iterationResult5.done)
const iterationResult5 = iterator.next();
t.ok(iterationResult5.done);
t.end()
})
t.end();
});
tap.test('iterates backwards', function (t) {
const dll = new DLL()
tap.test("iterates backwards", function(t) {
const dll = new DLL();
const node1 = DLL.createNode({id: 1})
const node2 = DLL.createNode({id: 2})
const node3 = DLL.createNode({id: 3})
const node4 = DLL.createNode({id: 4})
const node1 = DLL.createNode({ id: 1 });
const node2 = DLL.createNode({ id: 2 });
const node3 = DLL.createNode({ id: 3 });
const node4 = DLL.createNode({ id: 4 });
dll.insertBeginning(node1)
dll.insertBeginning(node2)
dll.insertBeginning(node3)
dll.insertBeginning(node4)
dll.insertBeginning(node1);
dll.insertBeginning(node2);
dll.insertBeginning(node3);
dll.insertBeginning(node4);
const iterator = new Iterator(dll, true)
const iterator = new Iterator(dll, true);
const iterationResult1 = iterator.next()
t.notOk(iterationResult1.done)
t.same(iterationResult1.value, node1)
const iterationResult1 = iterator.next();
t.notOk(iterationResult1.done);
t.same(iterationResult1.value, node1);
iterator.next()
iterator.next()
iterator.next();
iterator.next();
const iterationResult4 = iterator.next()
t.notOk(iterationResult4.done)
t.same(iterationResult4.value, node4)
const iterationResult4 = iterator.next();
t.notOk(iterationResult4.done);
t.same(iterationResult4.value, node4);
const iterationResult5 = iterator.next()
t.ok(iterationResult5.done)
const iterationResult5 = iterator.next();
t.ok(iterationResult5.done);
t.end()
})
t.end();
});
tap.test('iterates forward when adding nodes after creating iterator', function (t) {
const dll = new DLL()
tap.test("iterates forward when adding nodes after creating iterator", function(
t
) {
const dll = new DLL();
const node1 = DLL.createNode({id: 1})
const node2 = DLL.createNode({id: 2})
const node1 = DLL.createNode({ id: 1 });
const node2 = DLL.createNode({ id: 2 });
const iterator = new Iterator(dll)
const iterator = new Iterator(dll);
dll.insertBeginning(node1)
dll.insertBeginning(node2)
dll.insertBeginning(node1);
dll.insertBeginning(node2);
const iterationResult1 = iterator.next()
t.notOk(iterationResult1.done)
t.same(iterationResult1.value, node2)
const iterationResult1 = iterator.next();
t.notOk(iterationResult1.done);
t.same(iterationResult1.value, node2);
const iterationResult2 = iterator.next()
t.notOk(iterationResult2.done)
t.same(iterationResult2.value, node1)
const iterationResult2 = iterator.next();
t.notOk(iterationResult2.done);
t.same(iterationResult2.value, node1);
const iterationResult3 = iterator.next()
t.ok(iterationResult3.done)
const iterationResult3 = iterator.next();
t.ok(iterationResult3.done);
t.end()
})
t.end();
});
tap.test('iterates backwards when adding nodes after creating iterator', function (t) {
const dll = new DLL()
tap.test(
"iterates backwards when adding nodes after creating iterator",
function(t) {
const dll = new DLL();
const node1 = DLL.createNode({id: 1})
const node2 = DLL.createNode({id: 2})
const node1 = DLL.createNode({ id: 1 });
const node2 = DLL.createNode({ id: 2 });
const iterator = new Iterator(dll, true)
const iterator = new Iterator(dll, true);
dll.insertBeginning(node1)
dll.insertBeginning(node2)
dll.insertBeginning(node1);
dll.insertBeginning(node2);
const iterationResult1 = iterator.next()
t.notOk(iterationResult1.done)
t.same(iterationResult1.value, node1)
const iterationResult1 = iterator.next();
t.notOk(iterationResult1.done);
t.same(iterationResult1.value, node1);
const iterationResult2 = iterator.next()
t.notOk(iterationResult2.done)
t.same(iterationResult2.value, node2)
const iterationResult2 = iterator.next();
t.notOk(iterationResult2.done);
t.same(iterationResult2.value, node2);
const iterationResult3 = iterator.next()
t.ok(iterationResult3.done)
const iterationResult3 = iterator.next();
t.ok(iterationResult3.done);
t.end()
})
t.end();
}
);
tap.test('stops iterating when node is detached', function (t) {
const dll = new DLL()
const iterator = new Iterator(dll)
tap.test("stops iterating when node is detached", function(t) {
const dll = new DLL();
const iterator = new Iterator(dll);
const node1 = DLL.createNode({id: 1})
const node2 = DLL.createNode({id: 2})
const node1 = DLL.createNode({ id: 1 });
const node2 = DLL.createNode({ id: 2 });
dll.insertBeginning(node1)
dll.insertBeginning(node2)
dll.insertBeginning(node1);
dll.insertBeginning(node2);
const iterationResult1 = iterator.next()
t.notOk(iterationResult1.done)
t.same(iterationResult1.value, node2)
const iterationResult1 = iterator.next();
t.notOk(iterationResult1.done);
t.same(iterationResult1.value, node2);
dll.remove(node1)
dll.remove(node1);
const iterationResult3 = iterator.next()
t.ok(iterationResult3.done)
const iterationResult3 = iterator.next();
t.ok(iterationResult3.done);
t.end()
})
t.end();
});

@@ -1,28 +0,28 @@

var tap = require('tap')
var DLL = require('../lib/DoublyLinkedList')
var tap = require("tap");
var DLL = require("../lib/DoublyLinkedList");
tap.test('operations', function (t) {
var dll = new DLL()
tap.test("operations", function(t) {
var dll = new DLL();
var item1 = {id: 1}
var item2 = {id: 2}
var item3 = {id: 3}
var item4 = {id: 4}
var item1 = { id: 1 };
var item2 = { id: 2 };
var item3 = { id: 3 };
var item4 = { id: 4 };
dll.insertBeginning(DLL.createNode(item1))
t.equal(dll.head.data, item1)
dll.insertBeginning(DLL.createNode(item1));
t.equal(dll.head.data, item1);
dll.insertEnd(DLL.createNode(item2))
t.equal(dll.tail.data, item2)
dll.insertEnd(DLL.createNode(item2));
t.equal(dll.tail.data, item2);
dll.insertAfter(dll.tail, DLL.createNode(item3))
t.equal(dll.tail.data, item3)
dll.insertAfter(dll.tail, DLL.createNode(item3));
t.equal(dll.tail.data, item3);
dll.insertBefore(dll.tail, DLL.createNode(item4))
t.equal(dll.tail.data, item3)
dll.insertBefore(dll.tail, DLL.createNode(item4));
t.equal(dll.tail.data, item3);
dll.remove(dll.tail)
t.equal(dll.tail.data, item4)
dll.remove(dll.tail);
t.equal(dll.tail.data, item4);
t.end()
})
t.end();
});

@@ -1,17 +0,19 @@

'use strict'
"use strict";
const tap = require('tap')
const createPool = require('../').createPool
const tap = require("tap");
const createPool = require("../").createPool;
tap.test('acquireTimeout handles timed out acquire calls', function (t) {
tap.test("acquireTimeout handles timed out acquire calls", function(t) {
const factory = {
create: function () {
return new Promise(function (resolve) {
setTimeout(function () {
resolve({})
}, 100)
})
create: function() {
return new Promise(function(resolve) {
setTimeout(function() {
resolve({});
}, 100);
});
},
destroy: function () { return Promise.resolve() }
}
destroy: function() {
return Promise.resolve();
}
};
const config = {

@@ -21,53 +23,56 @@ acquireTimeoutMillis: 20,

log: false
}
};
const pool = createPool(factory, config)
const pool = createPool(factory, config);
pool.acquire()
.then(function (resource) {
t.fail('wooops')
})
.catch(function (err) {
t.match(err, /ResourceRequest timed out/)
return pool.drain()
})
.then(function () {
return pool.clear()
})
.then(function () {
})
.then(t.end)
.catch(t.error)
})
pool
.acquire()
.then(function(resource) {
t.fail("wooops");
})
.catch(function(err) {
t.match(err, /ResourceRequest timed out/);
return pool.drain();
})
.then(function() {
return pool.clear();
})
.then(function() {})
.then(t.end)
.catch(t.error);
});
tap.test('acquireTimeout handles non timed out acquire calls', function (t) {
const myResource = {}
tap.test("acquireTimeout handles non timed out acquire calls", function(t) {
const myResource = {};
const factory = {
create: function () {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(myResource)
}, 10)
})
create: function() {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(myResource);
}, 10);
});
},
destroy: function () { return Promise.resolve() }
}
destroy: function() {
return Promise.resolve();
}
};
const config = {
acquireTimeoutMillis: 400
}
};
const pool = createPool(factory, config)
const pool = createPool(factory, config);
pool.acquire()
.then(function (resource) {
t.equal(resource, myResource)
pool.release(resource)
return pool.drain()
})
.then(function () {
return pool.clear()
})
.then(t.end)
.catch(t.error)
})
pool
.acquire()
.then(function(resource) {
t.equal(resource, myResource);
pool.release(resource);
return pool.drain();
})
.then(function() {
return pool.clear();
})
.then(t.end)
.catch(t.error);
});

@@ -1,7 +0,7 @@

'use strict'
"use strict";
const tap = require('tap')
const createPool = require('../').createPool
const utils = require('./utils')
const ResourceFactory = utils.ResourceFactory
const tap = require("tap");
const createPool = require("../").createPool;
const utils = require("./utils");
const ResourceFactory = utils.ResourceFactory;

@@ -54,30 +54,30 @@ // tap.test('Pool expands only to max limit', function (t) {

tap.test('min and max limit defaults', function (t) {
const resourceFactory = new ResourceFactory()
tap.test("min and max limit defaults", function(t) {
const resourceFactory = new ResourceFactory();
const pool = createPool(resourceFactory)
const pool = createPool(resourceFactory);
t.equal(1, pool.max)
t.equal(0, pool.min)
utils.stopPool(pool)
t.end()
})
t.equal(1, pool.max);
t.equal(0, pool.min);
utils.stopPool(pool);
t.end();
});
tap.test('malformed min and max limits are ignored', function (t) {
const resourceFactory = new ResourceFactory()
tap.test("malformed min and max limits are ignored", function(t) {
const resourceFactory = new ResourceFactory();
const config = {
min: 'asf',
min: "asf",
max: []
}
const pool = createPool(resourceFactory, config)
};
const pool = createPool(resourceFactory, config);
t.equal(1, pool.max)
t.equal(0, pool.min)
utils.stopPool(pool)
t.end()
})
t.equal(1, pool.max);
t.equal(0, pool.min);
utils.stopPool(pool);
t.end();
});
tap.test('min greater than max sets to max', function (t) {
const resourceFactory = new ResourceFactory()
tap.test("min greater than max sets to max", function(t) {
const resourceFactory = new ResourceFactory();

@@ -87,18 +87,18 @@ const config = {

max: 3
}
const pool = createPool(resourceFactory, config)
};
const pool = createPool(resourceFactory, config);
t.equal(3, pool.max)
t.equal(3, pool.min)
utils.stopPool(pool)
t.end()
})
t.equal(3, pool.max);
t.equal(3, pool.min);
utils.stopPool(pool);
t.end();
});
tap.test('supports priority on borrow', function (t) {
tap.test("supports priority on borrow", function(t) {
// NOTE: this test is pretty opaque about what it's really testing/expecting...
let borrowTimeLow = 0
let borrowTimeHigh = 0
let borrowCount = 0
let borrowTimeLow = 0;
let borrowTimeHigh = 0;
let borrowCount = 0;
const resourceFactory = new ResourceFactory()
const resourceFactory = new ResourceFactory();

@@ -108,40 +108,45 @@ const config = {

priorityRange: 2
}
};
const pool = createPool(resourceFactory, config)
const pool = createPool(resourceFactory, config);
function lowPriorityOnFulfilled (obj) {
const time = Date.now()
if (time > borrowTimeLow) { borrowTimeLow = time }
borrowCount++
pool.release(obj)
function lowPriorityOnFulfilled(obj) {
const time = Date.now();
if (time > borrowTimeLow) {
borrowTimeLow = time;
}
borrowCount++;
pool.release(obj);
}
function highPriorityOnFulfilled (obj) {
const time = Date.now()
if (time > borrowTimeHigh) { borrowTimeHigh = time }
borrowCount++
pool.release(obj)
function highPriorityOnFulfilled(obj) {
const time = Date.now();
if (time > borrowTimeHigh) {
borrowTimeHigh = time;
}
borrowCount++;
pool.release(obj);
}
const operations = []
const operations = [];
for (let i = 0; i < 10; i++) {
const op = pool.acquire(1).then(lowPriorityOnFulfilled)
operations.push(op)
const op = pool.acquire(1).then(lowPriorityOnFulfilled);
operations.push(op);
}
for (let i = 0; i < 10; i++) {
const op = pool.acquire(0).then(highPriorityOnFulfilled)
operations.push(op)
const op = pool.acquire(0).then(highPriorityOnFulfilled);
operations.push(op);
}
Promise.all(operations).then(function () {
t.equal(20, borrowCount)
t.equal(true, borrowTimeLow >= borrowTimeHigh)
utils.stopPool(pool)
t.end()
})
.catch(t.threw)
})
Promise.all(operations)
.then(function() {
t.equal(20, borrowCount);
t.equal(true, borrowTimeLow >= borrowTimeHigh);
utils.stopPool(pool);
t.end();
})
.catch(t.threw);
});

@@ -185,4 +190,4 @@ // FIXME: bad test!

tap.test('evictor removes instances on idletimeout', function (t) {
const resourceFactory = new ResourceFactory()
tap.test("evictor removes instances on idletimeout", function(t) {
const resourceFactory = new ResourceFactory();
const config = {

@@ -193,86 +198,86 @@ min: 2,

evictionRunIntervalMillis: 10
}
const pool = createPool(resourceFactory, config)
};
const pool = createPool(resourceFactory, config);
setTimeout(function () {
pool.acquire()
.then((res) => {
t.ok(res.id > 1)
return pool.release(res)
})
.then(() => {
utils.stopPool(pool)
t.end()
})
}, 120)
})
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) {
const count = 5
let acquired = 0
tap.test("tests drain", function(t) {
const count = 5;
let acquired = 0;
const resourceFactory = new ResourceFactory()
const resourceFactory = new ResourceFactory();
const config = {
max: 2,
idletimeoutMillis: 300000
}
const pool = createPool(resourceFactory, config)
};
const pool = createPool(resourceFactory, config);
const operations = []
const operations = [];
function onAcquire (client) {
acquired += 1
t.equal(typeof client.id, 'number')
setTimeout(function () {
pool.release(client)
}, 250)
function onAcquire(client) {
acquired += 1;
t.equal(typeof client.id, "number");
setTimeout(function() {
pool.release(client);
}, 250);
}
// request 5 resources that release after 250ms
// request 5 resources that release after 250ms
for (let i = 0; i < count; i++) {
const op = pool.acquire().then(onAcquire)
operations.push(op)
const op = pool.acquire().then(onAcquire);
operations.push(op);
}
// FIXME: what does this assertion prove?
t.notEqual(count, acquired)
// FIXME: what does this assertion prove?
t.notEqual(count, acquired);
Promise.all(operations)
.then(function () {
return pool.drain()
})
.then(function () {
t.equal(count, acquired)
// short circuit the absurdly long timeouts above.
pool.clear()
})
.then(function () {
// subsequent calls to acquire should resolve an error.
return pool.acquire().then(t.fail,
function (e) {
t.type(e, Error)
})
})
.then(function () {
t.end()
})
})
.then(function() {
return pool.drain();
})
.then(function() {
t.equal(count, acquired);
// short circuit the absurdly long timeouts above.
pool.clear();
})
.then(function() {
// subsequent calls to acquire should resolve an error.
return pool.acquire().then(t.fail, function(e) {
t.type(e, Error);
});
})
.then(function() {
t.end();
});
});
tap.test('handle creation errors', function (t) {
let created = 0
tap.test("handle creation errors", function(t) {
let created = 0;
const resourceFactory = {
create: function () {
created++
create: function() {
created++;
if (created < 5) {
return Promise.reject(new Error('Error occurred.'))
return Promise.reject(new Error("Error occurred."));
} else {
return Promise.resolve({ id: created })
return Promise.resolve({ id: created });
}
},
destroy: function (client) {}
}
destroy: function(client) {}
};
const config = {
max: 1
}
};
const pool = createPool(resourceFactory, config)
const pool = createPool(resourceFactory, config);

@@ -291,165 +296,172 @@ // FIXME: this section no longer proves anything as factory

let called = false
pool.acquire()
.then(function (client) {
t.equal(typeof client.id, 'number')
called = true
pool.release(client)
})
.then(function () {
t.ok(called)
t.equal(pool.pending, 0)
utils.stopPool(pool)
t.end()
})
.catch(t.threw)
})
let called = false;
pool
.acquire()
.then(function(client) {
t.equal(typeof client.id, "number");
called = true;
pool.release(client);
})
.then(function() {
t.ok(called);
t.equal(pool.pending, 0);
utils.stopPool(pool);
t.end();
})
.catch(t.threw);
});
tap.test('handle creation errors for delayed creates', function (t) {
let attempts = 0
tap.test("handle creation errors for delayed creates", function(t) {
let attempts = 0;
const resourceFactory = {
create: function () {
attempts++
create: function() {
attempts++;
if (attempts <= 5) {
return Promise.reject(new Error('Error occurred.'))
return Promise.reject(new Error("Error occurred."));
} else {
return Promise.resolve({ id: attempts })
return Promise.resolve({ id: attempts });
}
},
destroy: function (client) { return Promise.resolve() }
}
destroy: function(client) {
return Promise.resolve();
}
};
const config = {
max: 1
}
};
const pool = createPool(resourceFactory, config)
const pool = createPool(resourceFactory, config);
let errorCount = 0
pool.on('factoryCreateError', function (err) {
t.ok(err instanceof Error)
errorCount++
})
let errorCount = 0;
pool.on("factoryCreateError", function(err) {
t.ok(err instanceof Error);
errorCount++;
});
let called = false
pool.acquire()
.then(function (client) {
t.equal(typeof client.id, 'number')
called = true
pool.release(client)
})
.then(function () {
t.ok(called)
t.equal(errorCount, 5)
t.equal(pool.pending, 0)
utils.stopPool(pool)
t.end()
})
.catch(t.threw)
})
let called = false;
pool
.acquire()
.then(function(client) {
t.equal(typeof client.id, "number");
called = true;
pool.release(client);
})
.then(function() {
t.ok(called);
t.equal(errorCount, 5);
t.equal(pool.pending, 0);
utils.stopPool(pool);
t.end();
})
.catch(t.threw);
});
tap.test('getPoolSize', function (t) {
let assertionCount = 0
const resourceFactory = new ResourceFactory()
tap.test("getPoolSize", function(t) {
let assertionCount = 0;
const resourceFactory = new ResourceFactory();
const config = {
max: 2
}
};
const pool = createPool(resourceFactory, config)
const pool = createPool(resourceFactory, config);
const borrowedResources = []
const borrowedResources = [];
t.equal(pool.size, 0)
assertionCount += 1
t.equal(pool.size, 0);
assertionCount += 1;
pool.acquire()
.then(function (obj) {
borrowedResources.push(obj)
t.equal(pool.size, 1)
assertionCount += 1
})
.then(function () {
return pool.acquire()
})
.then(function (obj) {
borrowedResources.push(obj)
t.equal(pool.size, 2)
assertionCount += 1
})
.then(function () {
pool.release(borrowedResources.shift())
pool.release(borrowedResources.shift())
})
.then(function () {
return pool.acquire()
})
.then(function (obj) {
// should still be 2
t.equal(pool.size, 2)
assertionCount += 1
pool.release(obj)
})
.then(function () {
t.equal(assertionCount, 4)
utils.stopPool(pool)
t.end()
})
.catch(t.threw)
})
pool
.acquire()
.then(function(obj) {
borrowedResources.push(obj);
t.equal(pool.size, 1);
assertionCount += 1;
})
.then(function() {
return pool.acquire();
})
.then(function(obj) {
borrowedResources.push(obj);
t.equal(pool.size, 2);
assertionCount += 1;
})
.then(function() {
pool.release(borrowedResources.shift());
pool.release(borrowedResources.shift());
})
.then(function() {
return pool.acquire();
})
.then(function(obj) {
// should still be 2
t.equal(pool.size, 2);
assertionCount += 1;
pool.release(obj);
})
.then(function() {
t.equal(assertionCount, 4);
utils.stopPool(pool);
t.end();
})
.catch(t.threw);
});
tap.test('availableObjectsCount', function (t) {
let assertionCount = 0
const resourceFactory = new ResourceFactory()
tap.test("availableObjectsCount", function(t) {
let assertionCount = 0;
const resourceFactory = new ResourceFactory();
const config = {
max: 2
}
};
const pool = createPool(resourceFactory, config)
const pool = createPool(resourceFactory, config);
const borrowedResources = []
const borrowedResources = [];
t.equal(pool.available, 0)
assertionCount += 1
t.equal(pool.available, 0);
assertionCount += 1;
pool.acquire()
.then(function (obj) {
borrowedResources.push(obj)
t.equal(pool.available, 0)
assertionCount += 1
}).then(function () {
return pool.acquire()
})
.then(function (obj) {
borrowedResources.push(obj)
t.equal(pool.available, 0)
assertionCount += 1
})
.then(function () {
pool.release(borrowedResources.shift())
t.equal(pool.available, 1)
assertionCount += 1
pool
.acquire()
.then(function(obj) {
borrowedResources.push(obj);
t.equal(pool.available, 0);
assertionCount += 1;
})
.then(function() {
return pool.acquire();
})
.then(function(obj) {
borrowedResources.push(obj);
t.equal(pool.available, 0);
assertionCount += 1;
})
.then(function() {
pool.release(borrowedResources.shift());
t.equal(pool.available, 1);
assertionCount += 1;
pool.release(borrowedResources.shift())
t.equal(pool.available, 2)
assertionCount += 1
})
.then(function () {
return pool.acquire()
})
.then(function (obj) {
t.equal(pool.available, 1)
assertionCount += 1
pool.release(obj)
pool.release(borrowedResources.shift());
t.equal(pool.available, 2);
assertionCount += 1;
})
.then(function() {
return pool.acquire();
})
.then(function(obj) {
t.equal(pool.available, 1);
assertionCount += 1;
pool.release(obj);
t.equal(pool.available, 2)
assertionCount += 1
})
.then(function () {
t.equal(assertionCount, 7)
utils.stopPool(pool)
t.end()
})
.catch(t.threw)
})
t.equal(pool.available, 2);
assertionCount += 1;
})
.then(function() {
t.equal(assertionCount, 7);
utils.stopPool(pool);
t.end();
})
.catch(t.threw);
});

@@ -529,221 +541,268 @@ // FIXME: bad test!

tap.test('do schedule again if error occured when creating new Objects async', function (t) {
// NOTE: we're simulating the first few resource attempts failing
let resourceCreationAttempts = 0
tap.test(
"do schedule again if error occured when creating new Objects async",
function(t) {
// NOTE: we're simulating the first few resource attempts failing
let resourceCreationAttempts = 0;
const factory = {
create: function () {
resourceCreationAttempts++
if (resourceCreationAttempts < 2) {
return Promise.reject(new Error('Create Error'))
}
return Promise.resolve({})
},
destroy: function (client) {}
}
const factory = {
create: function() {
resourceCreationAttempts++;
if (resourceCreationAttempts < 2) {
return Promise.reject(new Error("Create Error"));
}
return Promise.resolve({});
},
destroy: function(client) {}
};
const config = {
max: 1
const config = {
max: 1
};
const pool = createPool(factory, config);
// pool.acquire(function () {})
pool
.acquire()
.then(function(obj) {
t.equal(pool.available, 0);
pool.release(obj);
utils.stopPool(pool);
t.end();
})
.catch(t.threw);
}
);
const pool = createPool(factory, config)
// pool.acquire(function () {})
pool.acquire().then(function (obj) {
t.equal(pool.available, 0)
pool.release(obj)
utils.stopPool(pool)
t.end()
}).catch(t.threw)
})
tap.test('returns only valid object to the pool', function (t) {
tap.test("returns only valid object to the pool", function(t) {
const pool = createPool({
create: function () {
return Promise.resolve({ id: 'validId' })
create: function() {
return Promise.resolve({ id: "validId" });
},
destroy: function (client) {},
destroy: function(client) {},
max: 1
})
});
pool.acquire().then(function (obj) {
t.equal(pool.available, 0)
t.equal(pool.borrowed, 1)
pool
.acquire()
.then(function(obj) {
t.equal(pool.available, 0);
t.equal(pool.borrowed, 1);
// Invalid release
pool.release({}).catch(function (err) {
t.match(err.message, /Resource not currently part of this pool/)
}).then(function () {
t.equal(pool.available, 0)
t.equal(pool.borrowed, 1)
pool
.release({})
.catch(function(err) {
t.match(err.message, /Resource not currently part of this pool/);
})
.then(function() {
t.equal(pool.available, 0);
t.equal(pool.borrowed, 1);
// Valid release
pool.release(obj).catch(t.error)
t.equal(pool.available, 1)
t.equal(pool.borrowed, 0)
utils.stopPool(pool)
t.end()
// Valid release
pool.release(obj).catch(t.error);
t.equal(pool.available, 1);
t.equal(pool.borrowed, 0);
utils.stopPool(pool);
t.end();
});
})
}).catch(t.threw)
})
.catch(t.threw);
});
tap.test('validate acquires object from the pool', function (t) {
tap.test("validate acquires object from the pool", function(t) {
const pool = createPool({
create: function () {
return Promise.resolve({ id: 'validId' })
create: function() {
return Promise.resolve({ id: "validId" });
},
validate: function (resource) {
return Promise.resolve(true)
validate: function(resource) {
return Promise.resolve(true);
},
destroy: function (client) {},
destroy: function(client) {},
max: 1
})
});
pool.acquire()
.then(function (obj) {
t.equal(pool.available, 0)
t.equal(pool.borrowed, 1)
pool.release(obj)
utils.stopPool(pool)
t.end()
})
.catch(t.threw)
})
pool
.acquire()
.then(function(obj) {
t.equal(pool.available, 0);
t.equal(pool.borrowed, 1);
pool.release(obj);
utils.stopPool(pool);
t.end();
})
.catch(t.threw);
});
tap.test('release to pool should work', function (t) {
tap.test("release to pool should work", function(t) {
const pool = createPool({
create: function () {
return Promise.resolve({ id: 'validId' })
create: function() {
return Promise.resolve({ id: "validId" });
},
validate: function (resource) {
return Promise.resolve(true)
validate: function(resource) {
return Promise.resolve(true);
},
destroy: function (client) {},
destroy: function(client) {},
max: 1
})
});
pool.acquire()
.then(function (obj) {
t.equal(pool.available, 0)
t.equal(pool.borrowed, 1)
t.equal(pool.pending, 1)
pool.release(obj)
})
.catch(t.threw)
pool
.acquire()
.then(function(obj) {
t.equal(pool.available, 0);
t.equal(pool.borrowed, 1);
t.equal(pool.pending, 1);
pool.release(obj);
})
.catch(t.threw);
pool.acquire()
.then(function (obj) {
t.equal(pool.available, 0)
t.equal(pool.borrowed, 1)
t.equal(pool.pending, 0)
pool.release(obj)
utils.stopPool(pool)
t.end()
})
.catch(t.threw)
})
pool
.acquire()
.then(function(obj) {
t.equal(pool.available, 0);
t.equal(pool.borrowed, 1);
t.equal(pool.pending, 0);
pool.release(obj);
utils.stopPool(pool);
t.end();
})
.catch(t.threw);
});
tap.test('isBorrowedResource should return true for borrowed resource', function (t) {
const pool = createPool({
create: function () {
return Promise.resolve({ id: 'validId' })
},
validate: function (resource) {
return Promise.resolve(true)
},
destroy: function (client) {},
max: 1
})
tap.test(
"isBorrowedResource should return true for borrowed resource",
function(t) {
const pool = createPool({
create: function() {
return Promise.resolve({ id: "validId" });
},
validate: function(resource) {
return Promise.resolve(true);
},
destroy: function(client) {},
max: 1
});
pool.acquire()
.then(function (obj) {
t.equal(pool.isBorrowedResource(obj), true)
pool.release(obj)
utils.stopPool(pool)
t.end()
})
.catch(t.threw)
})
pool
.acquire()
.then(function(obj) {
t.equal(pool.isBorrowedResource(obj), true);
pool.release(obj);
utils.stopPool(pool);
t.end();
})
.catch(t.threw);
}
);
tap.test('isBorrowedResource should return false for released resource', function (t) {
tap.test(
"isBorrowedResource should return false for released resource",
function(t) {
const pool = createPool({
create: function() {
return Promise.resolve({ id: "validId" });
},
validate: function(resource) {
return Promise.resolve(true);
},
destroy: function(client) {},
max: 1
});
pool
.acquire()
.then(function(obj) {
pool.release(obj);
return obj;
})
.then(function(obj) {
t.equal(pool.isBorrowedResource(obj), false);
utils.stopPool(pool);
t.end();
})
.catch(t.threw);
}
);
tap.test("destroy should redispense", function(t) {
const pool = createPool({
create: function () {
return Promise.resolve({ id: 'validId' })
create: function() {
return Promise.resolve({ id: "validId" });
},
validate: function (resource) {
return Promise.resolve(true)
validate: function(resource) {
return Promise.resolve(true);
},
destroy: function (client) {},
destroy: function(client) {},
max: 1
})
});
pool.acquire()
.then(function (obj) {
pool.release(obj)
return obj
pool
.acquire()
.then(function(obj) {
t.equal(pool.available, 0);
t.equal(pool.borrowed, 1);
t.equal(pool.pending, 1);
pool.destroy(obj);
})
.then(function (obj) {
t.equal(pool.isBorrowedResource(obj), false)
utils.stopPool(pool)
t.end()
.catch(t.threw);
pool
.acquire()
.then(function(obj) {
t.equal(pool.available, 0);
t.equal(pool.borrowed, 1);
t.equal(pool.pending, 0);
pool.release(obj);
utils.stopPool(pool);
t.end();
})
.catch(t.threw)
})
.catch(t.threw);
});
tap.test('destroy should redispense', function (t) {
const pool = createPool({
create: function () {
return Promise.resolve({ id: 'validId' })
tap.test("evictor start with acquire when autostart is false", function(t) {
const pool = createPool(
{
create: function() {
return Promise.resolve({ id: "validId" });
},
validate: function(resource) {
return Promise.resolve(true);
},
destroy: function(client) {}
},
validate: function (resource) {
return Promise.resolve(true)
},
destroy: function (client) {},
max: 1
})
{
evictionRunIntervalMillis: 10000,
autostart: false
}
);
pool.acquire()
.then(function (obj) {
t.equal(pool.available, 0)
t.equal(pool.borrowed, 1)
t.equal(pool.pending, 1)
pool.destroy(obj)
})
.catch(t.threw)
t.equal(pool._scheduledEviction, null);
pool.acquire()
.then(function (obj) {
t.equal(pool.available, 0)
t.equal(pool.borrowed, 1)
t.equal(pool.pending, 0)
pool.release(obj)
utils.stopPool(pool)
t.end()
})
.catch(t.threw)
})
pool
.acquire()
.then(function(obj) {
t.notEqual(pool._scheduledEviction, null);
pool.release(obj);
utils.stopPool(pool);
t.end();
})
.catch(t.threw);
});
tap.test('evictor start with acquire when autostart is false', function (t) {
tap.test("use method", function(t) {
const pool = createPool({
create: function () {
return Promise.resolve({ id: 'validId' })
create: function() {
return Promise.resolve({
id: "validId"
});
},
validate: function (resource) {
return Promise.resolve(true)
},
destroy: function (client) {}
}, {
evictionRunIntervalMillis: 10000,
autostart: false
})
t.equal(pool._scheduledEviction, null)
pool.acquire()
.then(function (obj) {
t.notEqual(pool._scheduledEviction, null)
pool.release(obj)
utils.stopPool(pool)
t.end()
})
.catch(t.threw)
})
destroy: function(client) {}
});
const result = pool.use(function(resource) {
t.equal("validId", resource.id);
return Promise.resolve();
});
result.then(function() {
t.end();
});
});

@@ -1,60 +0,60 @@

var tap = require('tap')
var ResourceRequest = require('../lib/ResourceRequest')
var tap = require("tap");
var ResourceRequest = require("../lib/ResourceRequest");
tap.test('can be created', function (t) {
var create = function () {
var request = new ResourceRequest(undefined, Promise) // eslint-disable-line no-unused-vars
}
t.doesNotThrow(create)
t.end()
})
tap.test("can be created", function(t) {
var create = function() {
var request = new ResourceRequest(undefined, Promise); // eslint-disable-line no-unused-vars
};
t.doesNotThrow(create);
t.end();
});
tap.test('times out when created with a ttl', function (t) {
var reject = function (err) {
t.match(err, /ResourceRequest timed out/)
t.end()
}
var resolve = function (r) {
t.fail('should not resolve')
}
var request = new ResourceRequest(10, Promise) // eslint-disable-line no-unused-vars
tap.test("times out when created with a ttl", function(t) {
var reject = function(err) {
t.match(err, /ResourceRequest timed out/);
t.end();
};
var resolve = function(r) {
t.fail("should not resolve");
};
var request = new ResourceRequest(10, Promise); // eslint-disable-line no-unused-vars
request.promise.then(resolve, reject)
})
request.promise.then(resolve, reject);
});
tap.test('calls resolve when resolved', function (t) {
var resource = {}
var resolve = function (r) {
t.equal(r, resource)
t.end()
}
var reject = function (err) {
t.error(err)
}
var request = new ResourceRequest(undefined, Promise)
request.promise.then(resolve, reject)
request.resolve(resource)
})
tap.test("calls resolve when resolved", function(t) {
var resource = {};
var resolve = function(r) {
t.equal(r, resource);
t.end();
};
var reject = function(err) {
t.error(err);
};
var request = new ResourceRequest(undefined, Promise);
request.promise.then(resolve, reject);
request.resolve(resource);
});
tap.test('removeTimeout removes the timeout', function (t) {
var reject = function (err) {
t.error(err)
}
var request = new ResourceRequest(10, Promise)
request.promise.then(undefined, reject)
request.removeTimeout()
setTimeout(function () {
t.end()
}, 20)
})
tap.test("removeTimeout removes the timeout", function(t) {
var reject = function(err) {
t.error(err);
};
var request = new ResourceRequest(10, Promise);
request.promise.then(undefined, reject);
request.removeTimeout();
setTimeout(function() {
t.end();
}, 20);
});
tap.test('does nothing if resolved more than once', function (t) {
var request = new ResourceRequest(undefined, Promise)
t.doesNotThrow(function () {
request.resolve({})
})
t.doesNotThrow(function () {
request.resolve({})
})
t.end()
})
tap.test("does nothing if resolved more than once", function(t) {
var request = new ResourceRequest(undefined, Promise);
t.doesNotThrow(function() {
request.resolve({});
});
t.doesNotThrow(function() {
request.resolve({});
});
t.end();
});

@@ -5,23 +5,23 @@ /**

*/
var ResourceFactory = function ResourceFactory () {
this.created = 0
this.destroyed = 0
this.bin = []
}
var ResourceFactory = function ResourceFactory() {
this.created = 0;
this.destroyed = 0;
this.bin = [];
};
ResourceFactory.prototype.create = function () {
var id = this.created++
ResourceFactory.prototype.create = function() {
var id = this.created++;
var resource = {
id: id
}
return Promise.resolve(resource)
}
};
return Promise.resolve(resource);
};
ResourceFactory.prototype.destroy = function (resource) {
this.destroyed++
this.bin.push(resource)
return Promise.resolve()
}
ResourceFactory.prototype.destroy = function(resource) {
this.destroyed++;
this.bin.push(resource);
return Promise.resolve();
};
exports.ResourceFactory = ResourceFactory
exports.ResourceFactory = ResourceFactory;

@@ -34,7 +34,6 @@ /**

*/
exports.stopPool = function (pool) {
return pool.drain()
.then(function () {
return pool.clear()
})
}
exports.stopPool = function(pool) {
return pool.drain().then(function() {
return pool.clear();
});
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc