generic-pool
Advanced tools
Comparing version 3.2.0 to 3.3.0
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 |
17
index.js
@@ -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"); | ||
} | ||
} | ||
}; |
512
lib/Pool.js
@@ -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(); | ||
}); | ||
}; |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
94220
2332
6
377
1