lightning-pool
Advanced tools
Comparing version 1.1.2 to 1.2.0
678
lib/Pool.js
@@ -28,58 +28,56 @@ /* lightning-pool | ||
/** | ||
* Expose `Pool`. | ||
*/ | ||
class Pool extends EventEmitter { | ||
module.exports = Pool; | ||
/** | ||
* | ||
* @param {Object} factory | ||
* @param {Function} factory.create | ||
* @param {Function} factory.destroy | ||
* @param {Function} [factory.validate] | ||
* @param {Function} [factory.reset] | ||
* @param {Object} [options] | ||
* @constructor | ||
*/ | ||
constructor(factory, options) { | ||
super(); | ||
if (typeof factory !== 'object') | ||
throw new TypeError('`factory` object required'); | ||
/** | ||
* | ||
* @param {Object} factory | ||
* @param {Object} [options] | ||
* @constructor | ||
*/ | ||
function Pool(factory, options) { | ||
EventEmitter.apply(this); | ||
if (typeof factory !== 'object') | ||
throw new TypeError('`factory` object required'); | ||
if (typeof factory.create !== 'function') | ||
throw new TypeError('factory.create must be a function'); | ||
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 (factory.validate && typeof factory.validate !== 'function') | ||
throw new TypeError('factory.validate can be a function'); | ||
if (factory.validate && typeof factory.validate !== 'function') | ||
throw new TypeError('factory.validate can be a function'); | ||
if (factory.reset && typeof factory.reset !== 'function') | ||
throw new TypeError('factory.reset can be a function'); | ||
if (factory.reset && typeof factory.reset !== 'function') | ||
throw new TypeError('factory.reset can be a function'); | ||
const opts = this.options = new PoolOptions(this); | ||
options = options || {}; | ||
opts.acquireMaxRetries = options.acquireMaxRetries; | ||
opts.acquireRetryWait = options.acquireRetryWait; | ||
opts.acquireTimeoutMillis = options.acquireTimeoutMillis; | ||
opts.fifo = options.fifo; | ||
opts.idleTimeoutMillis = options.idleTimeoutMillis; | ||
opts.houseKeepInterval = options.houseKeepInterval; | ||
opts.min = options.min; | ||
opts.minIdle = options.minIdle; | ||
opts.max = options.max; | ||
opts.maxQueue = options.maxQueue; | ||
opts.resetOnReturn = options.resetOnReturn; | ||
opts.validation = options.validation; | ||
const opts = this.options = new PoolOptions(this); | ||
options = options || {}; | ||
opts.acquireMaxRetries = options.acquireMaxRetries; | ||
opts.acquireRetryWait = options.acquireRetryWait; | ||
opts.acquireTimeoutMillis = options.acquireTimeoutMillis; | ||
opts.fifo = options.fifo; | ||
opts.idleTimeoutMillis = options.idleTimeoutMillis; | ||
opts.houseKeepInterval = options.houseKeepInterval; | ||
opts.min = options.min; | ||
opts.minIdle = options.minIdle; | ||
opts.max = options.max; | ||
opts.maxQueue = options.maxQueue; | ||
opts.resetOnReturn = options.resetOnReturn; | ||
opts.validation = options.validation; | ||
this._factory = factory; | ||
this._requestQueue = new DoublyLinked(); | ||
this._allResources = new Map(); // List for all info objects | ||
this._acquiredResources = new DoublyLinked(); // List for acquired info objects | ||
this._idleResources = new DoublyLinked(); | ||
this._creating = 0; | ||
this._requestsProcessing = 0; | ||
this._state = PoolState.IDLE; | ||
} | ||
this._factory = factory; | ||
this._requestQueue = new DoublyLinked(); | ||
this._allResources = new Map(); // List for all info objects | ||
this._acquiredResources = new DoublyLinked(); // List for acquired info objects | ||
this._idleResources = new DoublyLinked(); | ||
this._creating = 0; | ||
this._requestsProcessing = 0; | ||
this._state = PoolState.IDLE; | ||
} | ||
Pool.prototype = { | ||
/** | ||
@@ -92,3 +90,3 @@ * Returns number of resources that are currently acquired | ||
return this._acquiredResources.length; | ||
}, | ||
} | ||
@@ -102,3 +100,3 @@ /** | ||
return this._idleResources.length; | ||
}, | ||
} | ||
@@ -112,3 +110,3 @@ /** | ||
return this._creating; | ||
}, | ||
} | ||
@@ -122,3 +120,3 @@ /** | ||
return this._requestQueue.length + this._requestsProcessing; | ||
}, | ||
} | ||
@@ -133,3 +131,3 @@ /** | ||
return this._allResources.size; | ||
}, | ||
} | ||
@@ -143,334 +141,318 @@ /** | ||
} | ||
}; | ||
Object.setPrototypeOf(Pool.prototype, EventEmitter.prototype); | ||
Pool.prototype.constructor = Pool; | ||
/** | ||
* Acquires `resource` from the pool or create a new one | ||
* | ||
* @param {Function} [callback] | ||
* @returns {Promise|Undefined} | ||
*/ | ||
acquire(callback) { | ||
if (!callback) | ||
return promisify.fromCallback(cb => this.acquire(cb)); | ||
try { | ||
this.start(); | ||
} catch (e) { | ||
return callback(e); | ||
} | ||
if (this.options.maxQueue && this.pending >= this.options.maxQueue) | ||
callback(new Error('Pool queue is full')); | ||
this._requestQueue.push(new PoolRequest(this, callback)); | ||
this._acquireNext(); | ||
} | ||
/** | ||
* Acquires `resource` from the pool or create a new one | ||
* | ||
* @param {Function} callback | ||
* @returns {Promise|Undefined} | ||
*/ | ||
Pool.prototype.acquire = function(callback) { | ||
const self = this; | ||
if (!callback) | ||
return promisify.fromCallback(function(cb) { | ||
self.acquire(cb); | ||
}); | ||
try { | ||
self.start(); | ||
} catch (e) { | ||
return callback(e); | ||
/** | ||
* Returns if a `resource` has been acquired from the pool and not yet released or destroyed. | ||
* | ||
* @param {*} resource | ||
* @return {boolean} | ||
*/ | ||
isAcquired(resource) { | ||
const rinf = this._allResources.get(resource); | ||
return !!(rinf && rinf._acquiredNode); | ||
} | ||
if (self.options.maxQueue && self.pending >= self.options.maxQueue) | ||
callback(new Error('Pool queue is full')); | ||
self._requestQueue.push(new PoolRequest(self, callback)); | ||
self._acquireNext(); | ||
}; | ||
/** | ||
* Returns if a `resource` has been acquired from the pool and not yet released or destroyed. | ||
* | ||
* @param {*} resource | ||
* @return {boolean} | ||
*/ | ||
Pool.prototype.isAcquired = function(resource) { | ||
const rinf = this._allResources.get(resource); | ||
return !!(rinf && rinf._acquiredNode); | ||
}; | ||
/** | ||
* Returns if the pool contains a `resource` | ||
* | ||
* @param {*} resource | ||
* @return {boolean} | ||
*/ | ||
includes(resource) { | ||
const rinf = this._allResources.get(resource); | ||
return !!rinf; | ||
} | ||
/** | ||
* Returns if the pool contains a `resource` | ||
* | ||
* @param {*} resource | ||
* @return {boolean} | ||
*/ | ||
Pool.prototype.includes = function(resource) { | ||
const rinf = this._allResources.get(resource); | ||
return !!rinf; | ||
}; | ||
/** | ||
* Releases an allocated `resource` and let it back to pool. | ||
* | ||
* @param {*} resource | ||
* @return {undefined} | ||
*/ | ||
release(resource) { | ||
try { | ||
const rinf = this._allResources.get(resource); | ||
if (!rinf) | ||
return; | ||
if (rinf.isAcquired) | ||
rinf.setIdle(); | ||
} finally { | ||
this._acquireNext(); | ||
} | ||
} | ||
/** | ||
* Releases an allocated `resource` and let it back to pool. | ||
* | ||
* @param {*} resource | ||
* @return {undefined} | ||
*/ | ||
Pool.prototype.release = function(resource) { | ||
const self = this; | ||
try { | ||
const rinf = self._allResources.get(resource); | ||
if (!rinf) | ||
return; | ||
if (rinf.isAcquired) | ||
rinf.setIdle(); | ||
} finally { | ||
self._acquireNext(); | ||
/** | ||
* Releases, destroys and removes any `resource` from `Pool`. | ||
* | ||
* @param {*} resource | ||
* @return {undefined} | ||
*/ | ||
destroy(resource) { | ||
try { | ||
const rinf = this._allResources.get(resource); | ||
if (!rinf) | ||
return; | ||
rinf.destroy(); | ||
} finally { | ||
this._acquireNext(); | ||
} | ||
} | ||
}; | ||
/** | ||
* Releases, destroys and removes any `resource` from `Pool`. | ||
* | ||
* @param {*} resource | ||
* @return {undefined} | ||
*/ | ||
Pool.prototype.destroy = function(resource) { | ||
const self = this; | ||
try { | ||
const rinf = self._allResources.get(resource); | ||
if (!rinf) | ||
/** | ||
* Starts the pool and begins creating of resources, starts house keeping and any other internal logic. | ||
* Note: This method is not need to be called. Pool instance will automatically be started when acquire() method is called | ||
* | ||
* @return {undefined} | ||
*/ | ||
start() { | ||
if (this._state >= PoolState.CLOSING) | ||
throw new Error('Closed pool can not be started again'); | ||
if (this._state === PoolState.STARTED) | ||
return; | ||
rinf.destroy(); | ||
} finally { | ||
self._acquireNext(); | ||
this._state = PoolState.STARTED; | ||
this._setHouseKeep(); | ||
this._ensureMin(); | ||
this._emitSafe('start'); | ||
} | ||
}; | ||
/** | ||
* Starts the pool and begins creating of resources, starts house keeping and any other internal logic. | ||
* Note: This method is not need to be called. Pool instance will automatically be started when acquire() method is called | ||
* | ||
* @return {undefined} | ||
*/ | ||
Pool.prototype.start = function() { | ||
if (this._state >= PoolState.CLOSING) | ||
throw new Error('Closed pool can not be started again'); | ||
if (this._state === PoolState.STARTED) | ||
return; | ||
this._state = PoolState.STARTED; | ||
this._setHouseKeep(); | ||
this._ensureMin(); | ||
this._emitSafe('start'); | ||
}; | ||
/** | ||
* Shuts down the pool and destroys all resources. | ||
* | ||
* @param {Boolean} force | ||
* @param {Function} [callback] | ||
* @return {Promise|undefined} | ||
*/ | ||
close(force, callback) { | ||
if (typeof force === 'function') { | ||
callback = force; | ||
force = false; | ||
} | ||
if (!callback) | ||
return promisify.fromCallback(cb => this.close(force, cb)); | ||
if (this._state !== PoolState.STARTED) | ||
return callback(); | ||
this._state = PoolState.CLOSING; | ||
this._requestQueue = new DoublyLinked(); | ||
this._requestsProcessing = 0; | ||
this._emitSafe('closing'); | ||
this.once('close', callback); | ||
if (force) | ||
this._acquiredResources.forEach(t => this.release(t.resource)); | ||
this._houseKeep(); | ||
} | ||
/** | ||
* Shuts down the pool and destroys all resources. | ||
* | ||
* @param {Boolean} force | ||
* @param {Function} callback | ||
* @return {Promise|undefined} | ||
*/ | ||
Pool.prototype.close = function(force, callback) { | ||
if (typeof force === 'function') { | ||
callback = force; | ||
force = false; | ||
/** | ||
* | ||
* @protected | ||
*/ | ||
_acquireNext() { | ||
if (this._state !== PoolState.STARTED || | ||
this._requestsProcessing >= this.options.max - this.acquired) | ||
return; | ||
const request = this._requestQueue.shift(); | ||
if (!request) | ||
return; | ||
this._requestsProcessing++; | ||
const doCallback = (err, rinf) => { | ||
this._requestsProcessing--; | ||
request.destroy(); | ||
try { | ||
if (rinf) { | ||
if (this._state !== PoolState.STARTED) { | ||
rinf.destroy(); | ||
return; | ||
} | ||
rinf.setAcquired(); | ||
this._ensureMin(); | ||
request.callback(null, rinf.resource); | ||
this._emitSafe('acquire', rinf.resource); | ||
} else request.callback(err); | ||
} catch (e) { | ||
// | ||
} | ||
this._acquireNext(); | ||
}; | ||
const rinf = this._idleResources.shift(); | ||
if (rinf) { | ||
rinf.setAcquired(); | ||
/* Validate resource */ | ||
if (this.options.validation && this._factory.validate) { | ||
return rinf.validate((err) => { | ||
/* Destroy resource on validation error */ | ||
if (err) { | ||
rinf.destroy(); | ||
this._emitSafe('validate-error', err, rinf.resource); | ||
this._requestsProcessing--; | ||
this._requestQueue.unshift(request); | ||
this._acquireNext(); | ||
} else doCallback(err, rinf); | ||
}); | ||
} | ||
return doCallback(null, rinf); | ||
} | ||
/** There is no idle resource. We need to create new one **/ | ||
this._createObject(request, doCallback); | ||
} | ||
const self = this; | ||
if (!callback) | ||
return promisify.fromCallback(function(cb) { | ||
self.close(force, cb); | ||
}); | ||
if (this._state !== PoolState.STARTED) | ||
return callback(); | ||
self._state = PoolState.CLOSING; | ||
self._requestQueue = new DoublyLinked(); | ||
self._requestsProcessing = 0; | ||
self._emitSafe('closing'); | ||
self.once('close', callback); | ||
if (force) { | ||
self._acquiredResources.forEach(function(t) { | ||
self.release(t.resource); | ||
}); | ||
} | ||
self._houseKeep(); | ||
}; | ||
/** | ||
* | ||
* @private | ||
*/ | ||
Pool.prototype._acquireNext = function() { | ||
if (this._state !== PoolState.STARTED || | ||
this._requestsProcessing >= this.options.max - this.acquired) | ||
return; | ||
const request = this._requestQueue.shift(); | ||
if (!request) | ||
return; | ||
/** | ||
* Creates new resource object | ||
* @param {Object} request | ||
* @param {Function} [callback] | ||
* @protected | ||
*/ | ||
_createObject(request, callback) { | ||
const maxRetries = this.options.acquireMaxRetries; | ||
let tries = 0; | ||
let aborted; | ||
this._creating++; | ||
const self = this; | ||
self._requestsProcessing++; | ||
const doCallback = function(err, rinf) { | ||
self._requestsProcessing--; | ||
request.destroy(); | ||
try { | ||
if (rinf) { | ||
if (self._state !== PoolState.STARTED) { | ||
rinf.destroy(); | ||
const handleCallback = (err, obj) => { | ||
const rinf = obj ? new ResourceInfo(this, obj) : null; | ||
if (err) { | ||
if (request.timedOut) | ||
return; | ||
tries++; | ||
this._emitSafe('error', err, | ||
{ | ||
requestTime: request.created, | ||
tries: tries, | ||
maxRetries: this.options.acquireMaxRetries | ||
}); | ||
if (aborted || tries >= maxRetries) { | ||
this._creating--; | ||
return callback && callback(err); | ||
} | ||
rinf.setAcquired(); | ||
self._ensureMin(); | ||
request.callback(null, rinf.resource); | ||
self._emitSafe('acquire', rinf.resource); | ||
} else request.callback(err); | ||
} catch (e) { | ||
// | ||
} | ||
self._acquireNext(); | ||
}; | ||
return setTimeout(() => tryCreate(), this.options.acquireRetryWait); | ||
} | ||
this._creating--; | ||
if (this._allResources.has(obj)) | ||
return callback(new Error('Factory error. Resource already in pool')); | ||
const rinf = self._idleResources.shift(); | ||
if (rinf) { | ||
rinf.setAcquired(); | ||
/* Validate resource */ | ||
if (self.options.validation && self._factory.validate) { | ||
return rinf.validate(function(err) { | ||
/* Destroy resource on validation error */ | ||
if (err) { | ||
rinf.destroy(); | ||
self._emitSafe('validate-error', err, rinf.resource); | ||
self._requestsProcessing--; | ||
self._requestQueue.unshift(request); | ||
self._acquireNext(); | ||
} else doCallback(err, rinf); | ||
}); | ||
} | ||
return doCallback(null, rinf); | ||
} | ||
/** There is no idle resource. We need to create new one **/ | ||
self._createObject(request, doCallback); | ||
}; | ||
this._allResources.set(obj, rinf); | ||
rinf.setIdle(); | ||
if (callback && !request.timedOut) | ||
callback(null, rinf); | ||
this._emitSafe('create', obj); | ||
}; | ||
/** | ||
* Creates new resource object | ||
* @param {Object} request | ||
* @param {Function} callback | ||
* @private | ||
*/ | ||
Pool.prototype._createObject = function(request, callback) { | ||
const self = this; | ||
const maxRetries = self.options.acquireMaxRetries; | ||
var tries = 0; | ||
var aborted; | ||
self._creating++; | ||
handleCallback.abort = (e) => { | ||
aborted = true; | ||
handleCallback(e || new Error('Factory aborted')); | ||
}; | ||
function handleCallback(err, obj) { | ||
const rinf = obj ? new ResourceInfo(self, obj) : null; | ||
if (err) { | ||
if (request.timedOut) | ||
return; | ||
tries++; | ||
self._emitSafe('error', err, | ||
{ | ||
requestTime: request.created, | ||
tries: tries, | ||
maxRetries: self.options.acquireMaxRetries | ||
}); | ||
if (aborted || tries >= maxRetries) { | ||
self._creating--; | ||
return callback && callback(err); | ||
const tryCreate = () => { | ||
try { | ||
handleCallback.tries = tries; | ||
handleCallback.maxRetries = maxRetries; | ||
const o = this._factory.create(handleCallback); | ||
if (promisify.isPromise(o)) | ||
o.then(obj => handleCallback(null, obj)).catch(handleCallback); | ||
} catch (e) { | ||
handleCallback(e); | ||
} | ||
return setTimeout(function() { | ||
tryCreate(); | ||
}, self.options.acquireRetryWait); | ||
} | ||
self._creating--; | ||
if (self._allResources.has(obj)) | ||
return callback(new Error('Factory error. Resource already in pool')); | ||
}; | ||
self._allResources.set(obj, rinf); | ||
rinf.setIdle(); | ||
if (callback && !request.timedOut) | ||
callback(null, rinf); | ||
self._emitSafe('create', obj); | ||
tryCreate(); | ||
} | ||
function abortFn(e) { | ||
aborted = true; | ||
handleCallback(e || new Error('Factory aborted')); | ||
} | ||
handleCallback.abort = abortFn; | ||
function tryCreate() { | ||
/** | ||
* Prevents errors while calling emit() | ||
* @protected | ||
*/ | ||
_emitSafe() { | ||
try { | ||
handleCallback.tries = tries; | ||
handleCallback.maxRetries = maxRetries; | ||
const o = self._factory.create(handleCallback); | ||
if (promisify.isPromise(o)) | ||
o.then(function(obj) { | ||
handleCallback(null, obj); | ||
}).catch(handleCallback); | ||
this.emit.apply(this, arguments); | ||
} catch (e) { | ||
handleCallback(e); | ||
// Do nothing | ||
} | ||
} | ||
tryCreate(); | ||
}; | ||
/** | ||
* | ||
* @protected | ||
*/ | ||
_setHouseKeep() { | ||
clearTimeout(this._houseKeepHandle); | ||
this._houseKeepHandle = null; | ||
if (this._state !== PoolState.STARTED || !this.options.houseKeepInterval) | ||
return; | ||
this._houseKeepHandle = setTimeout(() => { | ||
this._houseKeep(); | ||
this._setHouseKeep(); | ||
}, this.options.houseKeepInterval); | ||
}; | ||
/** | ||
* Prevents errors while calling emit() | ||
* @private | ||
*/ | ||
Pool.prototype._emitSafe = function() { | ||
try { | ||
this.emit.apply(this, arguments); | ||
} catch (e) { | ||
// Do nothing | ||
/** | ||
* | ||
* @protected | ||
*/ | ||
_houseKeep() { | ||
clearTimeout(this._houseKeepHandle); | ||
const isClosing = this._state === PoolState.CLOSING; | ||
const now = Date.now(); | ||
let m = this._allResources.size - this.options.min; | ||
let n = this._idleResources.length - this.options.minIdle; | ||
if (isClosing || (m > 0 && n > 0)) { | ||
this._idleResources.every(t => { | ||
if (isClosing || | ||
t.iddleTime + this.options.idleTimeoutMillis < now) { | ||
t.destroy(); | ||
return isClosing || ((--n) && (--m)); | ||
} | ||
}); | ||
} | ||
if (isClosing) { | ||
if (this._allResources.size) | ||
/* Check again 5 ms later */ | ||
setTimeout(() => this._houseKeep(), 5); | ||
else { | ||
this._state = PoolState.CLOSED; | ||
this._requestsProcessing = 0; | ||
this._emitSafe('close'); | ||
} | ||
} | ||
} | ||
}; | ||
/** | ||
* | ||
* @private | ||
*/ | ||
Pool.prototype._setHouseKeep = function() { | ||
clearTimeout(this._houseKeepHandle); | ||
this._houseKeepHandle = null; | ||
if (this._state !== PoolState.STARTED || !this.options.houseKeepInterval) | ||
return; | ||
const self = this; | ||
this._houseKeepHandle = setTimeout(function() { | ||
self._houseKeep(); | ||
self._setHouseKeep(); | ||
}, self.options.houseKeepInterval); | ||
}; | ||
Pool.prototype._houseKeep = function() { | ||
clearTimeout(this._houseKeepHandle); | ||
const self = this; | ||
const isClosing = self._state === PoolState.CLOSING; | ||
const now = Date.now(); | ||
var m = self._allResources.size - self.options.min; | ||
var n = self._idleResources.length - self.options.minIdle; | ||
if (isClosing || (m > 0 && n > 0)) { | ||
self._idleResources.every(function(t) { | ||
if (isClosing || | ||
t.iddleTime + self.options.idleTimeoutMillis < now) { | ||
t.destroy(); | ||
return isClosing || ((--n) && (--m)); | ||
} | ||
/** | ||
* | ||
* @protected | ||
*/ | ||
_ensureMin() { | ||
process.nextTick(() => { | ||
let k = Math.max(this.options.min - this._allResources.size, | ||
this.options.minIdle - this._idleResources.length); | ||
while (k-- > 0) | ||
this._createObject(new PoolRequest(this)); | ||
}); | ||
} | ||
if (isClosing) { | ||
if (self._allResources.size) | ||
/* Check again 5 ms later */ | ||
setTimeout(function() { | ||
self._houseKeep(); | ||
}, 5); | ||
else { | ||
self._state = PoolState.CLOSED; | ||
self._requestsProcessing = 0; | ||
self._emitSafe('close'); | ||
} | ||
} | ||
}; | ||
} | ||
Pool.PoolState = PoolState; | ||
/** | ||
* | ||
* @private | ||
* Expose `Pool`. | ||
*/ | ||
Pool.prototype._ensureMin = function() { | ||
const self = this; | ||
process.nextTick(function() { | ||
var k = Math.max(self.options.min - self._allResources.size, | ||
self.options.minIdle - self._idleResources.length); | ||
while (k-- > 0) | ||
self._createObject(new PoolRequest(self)); | ||
}); | ||
}; | ||
Pool.PoolState = PoolState; | ||
module.exports = Pool; |
@@ -30,21 +30,15 @@ /* lightning-pool | ||
/** | ||
* Expose `PoolOptions`. | ||
*/ | ||
class PoolOptions { | ||
/** | ||
* @param {Pool} pool | ||
* @constructor | ||
*/ | ||
constructor(pool) { | ||
this.pool = pool; | ||
this._priv = Object.assign({}, defaultValues); | ||
} | ||
module.exports = PoolOptions; | ||
/** | ||
* | ||
* @constructor | ||
*/ | ||
function PoolOptions(pool) { | ||
this.pool = pool; | ||
this._priv = Object.assign({}, defaultValues); | ||
} | ||
PoolOptions.prototype = { | ||
get acquireMaxRetries() { | ||
return this._priv.acquireMaxRetries; | ||
}, | ||
} | ||
@@ -54,7 +48,7 @@ set acquireMaxRetries(val) { | ||
(val || defaultValues.acquireMaxRetries); | ||
}, | ||
} | ||
get acquireRetryWait() { | ||
return this._priv.acquireRetryWait; | ||
}, | ||
} | ||
@@ -64,7 +58,7 @@ set acquireRetryWait(val) { | ||
(val || defaultValues.acquireRetryWait); | ||
}, | ||
} | ||
get acquireTimeoutMillis() { | ||
return this._priv.acquireTimeoutMillis; | ||
}, | ||
} | ||
@@ -74,7 +68,7 @@ set acquireTimeoutMillis(val) { | ||
(val || defaultValues.acquireTimeoutMillis); | ||
}, | ||
} | ||
get fifo() { | ||
return this._priv.fifo; | ||
}, | ||
} | ||
@@ -84,7 +78,7 @@ set fifo(val) { | ||
defaultValues.fifo : !!val; | ||
}, | ||
} | ||
get idleTimeoutMillis() { | ||
return this._priv.idleTimeoutMillis; | ||
}, | ||
} | ||
@@ -95,7 +89,7 @@ set idleTimeoutMillis(val) { | ||
this.pool._setHouseKeep(); | ||
}, | ||
} | ||
get houseKeepInterval() { | ||
return this._priv.houseKeepInterval; | ||
}, | ||
} | ||
@@ -106,7 +100,7 @@ set houseKeepInterval(val) { | ||
this.pool._setHouseKeep(); | ||
}, | ||
} | ||
get min() { | ||
return this._priv.min; | ||
}, | ||
} | ||
@@ -119,7 +113,7 @@ set min(val) { | ||
this.pool._setHouseKeep(); | ||
}, | ||
} | ||
get minIdle() { | ||
return this._priv.minIdle; | ||
}, | ||
} | ||
@@ -130,7 +124,7 @@ set minIdle(val) { | ||
this.pool._setHouseKeep(); | ||
}, | ||
} | ||
get max() { | ||
return this._priv.max; | ||
}, | ||
} | ||
@@ -143,7 +137,7 @@ set max(val) { | ||
this.pool._setHouseKeep(); | ||
}, | ||
} | ||
get maxQueue() { | ||
return this._priv.maxQueue; | ||
}, | ||
} | ||
@@ -153,7 +147,7 @@ set maxQueue(val) { | ||
(val || defaultValues.maxQueue); | ||
}, | ||
} | ||
get resetOnReturn() { | ||
return this._priv.resetOnReturn; | ||
}, | ||
} | ||
@@ -163,7 +157,7 @@ set resetOnReturn(val) { | ||
defaultValues.resetOnReturn : !!val; | ||
}, | ||
} | ||
get validation() { | ||
return this._priv.validation; | ||
}, | ||
} | ||
@@ -174,2 +168,8 @@ set validation(val) { | ||
} | ||
}; | ||
} | ||
/** | ||
* Expose `PoolOptions`. | ||
*/ | ||
module.exports = PoolOptions; |
@@ -10,2 +10,30 @@ /* lightning-pool | ||
class PoolRequest { | ||
/** | ||
* @param {Pool} pool | ||
* @param {function} [callback] | ||
* @constructor | ||
*/ | ||
constructor(pool, callback) { | ||
this.created = Date.now(); | ||
this.callback = callback; | ||
this.pool = pool; | ||
if (pool.options.acquireTimeoutMillis) { | ||
this.timeoutHandle = setTimeout(() => { | ||
this.timedOut = true; | ||
this.destroy(); | ||
pool._emitSafe('request-timeout'); | ||
callback(new Error('Request timed out')); | ||
}, pool.options.acquireTimeoutMillis); | ||
} | ||
} | ||
destroy() { | ||
if (this.timeoutHandle) | ||
clearTimeout(this.timeoutHandle); | ||
} | ||
} | ||
/** | ||
@@ -16,25 +44,1 @@ * Expose `PoolRequest`. | ||
module.exports = PoolRequest; | ||
/** | ||
* | ||
* @constructor | ||
*/ | ||
function PoolRequest(pool, callback) { | ||
this.created = Date.now(); | ||
this.callback = callback; | ||
this.pool = pool; | ||
if (pool.options.acquireTimeoutMillis) { | ||
const self = this; | ||
self.timeoutHandle = setTimeout(function() { | ||
self.timedOut = true; | ||
self.destroy(); | ||
pool._emitSafe('request-timeout'); | ||
callback(new Error('Request timed out')); | ||
}, pool.options.acquireTimeoutMillis); | ||
} | ||
} | ||
PoolRequest.prototype.destroy = function() { | ||
if (this.timeoutHandle) | ||
clearTimeout(this.timeoutHandle); | ||
}; |
@@ -18,19 +18,15 @@ /* lightning-pool | ||
/** | ||
* Expose `ResourceInfo`. | ||
*/ | ||
class ResourceInfo { | ||
module.exports = ResourceInfo; | ||
/** | ||
* @param {Pool} pool | ||
* @param {*} resource | ||
* @constructor | ||
*/ | ||
constructor(pool, resource) { | ||
this.pool = pool; | ||
this.resource = resource; | ||
this.state = -1; | ||
} | ||
/** | ||
* | ||
* @constructor | ||
*/ | ||
function ResourceInfo(pool, resource) { | ||
this.pool = pool; | ||
this.resource = resource; | ||
this.state = -1; | ||
} | ||
const proto = ResourceInfo.prototype = { | ||
get isAcquired() { | ||
@@ -40,106 +36,108 @@ return this.state === ResourceState.ACQUIRED || this.state === | ||
} | ||
}; | ||
proto.constructor = ResourceInfo; | ||
proto.setAcquired = function() { | ||
if (this.isAcquired) | ||
return; | ||
this._detach(); | ||
this.state = ResourceState.ACQUIRED; | ||
this.pool._acquiredResources.push(this); | ||
this._acquiredNode = this.pool._acquiredResources.tail; | ||
}; | ||
setAcquired() { | ||
if (this.isAcquired) | ||
return; | ||
this._detach(); | ||
this.state = ResourceState.ACQUIRED; | ||
this.pool._acquiredResources.push(this); | ||
this._acquiredNode = this.pool._acquiredResources.tail; | ||
} | ||
proto.setIdle = function() { | ||
const self = this; | ||
const isAcquired = self.state === ResourceState.ACQUIRED; | ||
setIdle() { | ||
const isAcquired = this.state === ResourceState.ACQUIRED; | ||
const doSetIdle = function() { | ||
self._detach(); | ||
self.iddleTime = Date.now(); | ||
self.state = ResourceState.IDLE; | ||
const doSetIdle = () => { | ||
this._detach(); | ||
this.iddleTime = Date.now(); | ||
this.state = ResourceState.IDLE; | ||
if (self.pool.options.fifo) { | ||
self.pool._idleResources.push(self); | ||
self._idleNode = self.pool._idleResources.tail; | ||
} else { | ||
self.pool._idleResources.unshift(self); | ||
self._idleNode = self.pool._idleResources.head; | ||
if (this.pool.options.fifo) { | ||
this.pool._idleResources.push(this); | ||
this._idleNode = this.pool._idleResources.tail; | ||
} else { | ||
this.pool._idleResources.unshift(this); | ||
this._idleNode = this.pool._idleResources.head; | ||
} | ||
if (isAcquired) | ||
this.pool.emit('return', this.resource); | ||
this.pool._acquireNext(); | ||
}; | ||
if (isAcquired && this.pool.options.resetOnReturn && | ||
this.pool._factory.reset) { | ||
const handleReset = (err) => { | ||
if (err) | ||
return this.destroy(); | ||
doSetIdle(); | ||
}; | ||
const o = this.pool._factory.reset(this.resource, handleReset); | ||
if (promisify.isPromise(o)) | ||
o.then(handleReset).catch(handleReset); | ||
return; | ||
} | ||
if (isAcquired) | ||
self.pool.emit('return', self.resource); | ||
self.pool._acquireNext(); | ||
}; | ||
doSetIdle(); | ||
} | ||
if (isAcquired && self.pool.options.resetOnReturn && | ||
self.pool._factory.reset) { | ||
const handleReset = function(err) { | ||
validate(callback) { | ||
this.state = ResourceState.VALIDATION; | ||
try { | ||
const o = this.pool._factory.validate(this.resource, callback); | ||
if (promisify.isPromise(o)) | ||
o.then(callback).catch(callback); | ||
} catch (e) { | ||
callback(e); | ||
} | ||
} | ||
/** | ||
* Destroys resource object | ||
* @private | ||
*/ | ||
destroy() { | ||
const pool = this.pool; | ||
this._detach(); | ||
const handleCallback = (err) => { | ||
pool._allResources.delete(this.resource); | ||
if (err) | ||
return self.destroy(); | ||
doSetIdle(); | ||
pool._emitSafe('destroy-error', err, this.resource); | ||
pool._emitSafe('destroy', this.resource); | ||
this.destroyed = true; | ||
}; | ||
const o = self.pool._factory.reset(self.resource, handleReset); | ||
if (promisify.isPromise(o)) | ||
o.then(handleReset).catch(handleReset); | ||
return; | ||
try { | ||
const o = pool._factory.destroy(self.resource, handleCallback); | ||
if (promisify.isPromise(o)) | ||
o.then(obj => handleCallback(undefined, obj)).catch(handleCallback); | ||
} catch (e) { | ||
handleCallback(e); | ||
} | ||
} | ||
doSetIdle(); | ||
}; | ||
proto.validate = function(callback) { | ||
this.state = ResourceState.VALIDATION; | ||
try { | ||
const o = this.pool._factory.validate(this.resource, callback); | ||
if (promisify.isPromise(o)) | ||
o.then(callback).catch(callback); | ||
} catch (e) { | ||
callback(e); | ||
_detach() { | ||
switch (this.state) { | ||
case ResourceState.IDLE: | ||
this.iddleTime = null; | ||
/* istanbul ignore next*/ | ||
if (this._idleNode) | ||
this._idleNode.remove(); | ||
this._idleNode = null; | ||
break; | ||
case ResourceState.ACQUIRED: | ||
case ResourceState.VALIDATION: | ||
/* istanbul ignore next*/ | ||
if (this._acquiredNode) | ||
this._acquiredNode.remove(); | ||
this._acquiredNode = null; | ||
break; | ||
} | ||
} | ||
}; | ||
} | ||
/** | ||
* Destroys resource object | ||
* @private | ||
* Expose `ResourceInfo`. | ||
*/ | ||
proto.destroy = function() { | ||
const self = this; | ||
const pool = this.pool; | ||
self._detach(); | ||
function handleCallback(err) { | ||
pool._allResources.delete(self.resource); | ||
if (err) | ||
pool._emitSafe('destroy-error', err, self.resource); | ||
pool._emitSafe('destroy', self.resource); | ||
self.destroyed = true; | ||
} | ||
try { | ||
const o = pool._factory.destroy(self.resource, handleCallback); | ||
if (promisify.isPromise(o)) | ||
o.then(function(obj) { | ||
handleCallback(undefined, obj); | ||
}).catch(handleCallback); | ||
} catch (e) { | ||
handleCallback(e); | ||
} | ||
}; | ||
proto._detach = function() { | ||
switch (this.state) { | ||
case ResourceState.IDLE: | ||
this.iddleTime = null; | ||
/* istanbul ignore next*/ | ||
if (this._idleNode) | ||
this._idleNode.remove(); | ||
this._idleNode = null; | ||
break; | ||
case ResourceState.ACQUIRED: | ||
case ResourceState.VALIDATION: | ||
/* istanbul ignore next*/ | ||
if (this._acquiredNode) | ||
this._acquiredNode.remove(); | ||
this._acquiredNode = null; | ||
break; | ||
} | ||
}; | ||
module.exports = ResourceInfo; |
{ | ||
"name": "lightning-pool", | ||
"description": "Fastest object pool implementation for JavaScript", | ||
"version": "1.1.2", | ||
"version": "1.2.0", | ||
"author": "Panates Ltd.", | ||
@@ -17,10 +17,10 @@ "contributors": [ | ||
"doublylinked": "^1.0.7", | ||
"putil-promisify": "^1.1.0" | ||
"putil-promisify": "^1.2.0" | ||
}, | ||
"devDependencies": { | ||
"babel-eslint": "^8.2.2", | ||
"eslint": "^4.18.2", | ||
"babel-eslint": "^8.2.6", | ||
"eslint": "^5.3.0", | ||
"eslint-config-google": "^0.9.1", | ||
"istanbul": "^0.4.5", | ||
"mocha": "^5.0.4" | ||
"mocha": "^5.2.0" | ||
}, | ||
@@ -27,0 +27,0 @@ "engines": { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
36346
718
Updatedputil-promisify@^1.2.0