Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Factory can be asked to validate pooled objects #54

Merged
merged 1 commit into from

2 participants

Teemu Ikonen James Cooper
Teemu Ikonen

Disclaimer: This is feature I needed but not sure if it's something that belongs to common codebase, so pull request just in case.

Some type of pooled objects, like TCP connections, can be unexpectedly invalidated by external reasons while they are in the pool. For example, socket can timeout or be closed by peer. Also peer restart can cause all socket objects in pool to become instantly "invalid".

Naturally its pool users responsibility to check if acquired object is still valid and remove it, but for simplicity it's good to have separate validation factory function to do sanity checks.

Trivial example:

...
validate: function(socket)  { return socket.writable; },
...

Validate is called only on acquire for pooled objects, not for freshly created. If validate returns false, pool destroys object.

James Cooper

Sorry I never reviewed this. This is a good idea. I'll merge it and get it in the next npm release.

James Cooper coopernurse merged commit a6db3af into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 45 additions and 6 deletions.
  1. +17 −6 lib/generic-pool.js
  2. +28 −0 test/generic-pool.test.js
23 lib/generic-pool.js
View
@@ -70,11 +70,15 @@ var PriorityQueue = function(size) {
* @param {Function} factory.destroy
* Should gently close any resources that the item is using.
* Called before the items is destroyed.
+ * @param {Function} factory.validate
+ * Should return true if connection is still valid and false
+ * If it should be removed from pool. Called before item is
+ * acquired from pool.
* @param {Number} factory.max
- * Maximum numnber of items that can exist at the same time. Default: 1.
+ * Maximum number of items that can exist at the same time. Default: 1.
* Any further acquire requests will be pushed to the waiting list.
* @param {Number} factory.min
- * Minimum numnber of items in pool (including in-use). Default: 0.
+ * Minimum number of items in pool (including in-use). Default: 0.
* When the pool is created, or a resource destroyed, this minimum will
* be checked. If the pool resource count is below the minimum, a new
* resource will be created and added to the pool.
@@ -117,6 +121,8 @@ exports.Pool = function (factory) {
) :
function () {};
+ factory.validate = factory.validate || function() { return true; };
+
factory.max = parseInt(factory.max, 10);
factory.min = parseInt(factory.min, 10);
@@ -228,13 +234,18 @@ exports.Pool = function (factory) {
log("dispense() clients=" + waitingCount + " available=" + availableObjects.length, 'info');
if (waitingCount > 0) {
- if (availableObjects.length > 0) {
+ while (availableObjects.length > 0) {
log("dispense() - reusing obj", 'verbose');
- objWithTimeout = availableObjects.shift();
+ objWithTimeout = availableObjects[0];
+ if (!factory.validate(objWithTimeout.obj)) {
+ me.destroy(objWithTimeout.obj);
+ continue;
+ }
+ availableObjects.shift();
clientCb = waitingClients.dequeue();
- clientCb(err, objWithTimeout.obj);
+ return clientCb(err, objWithTimeout.obj);
}
- else if (count < factory.max) {
+ if (count < factory.max) {
createResource();
}
}
28 test/generic-pool.test.js
View
@@ -559,6 +559,34 @@ module.exports = {
assert.equal(pool.availableObjectsCount(), 0);
},
+ 'removes from available objects on validation failure': function(beforeExit){
+ var destroyCalled = false,
+ validateCalled = false,
+ count = 0;
+ var factory = {
+ name: 'test',
+ create: function(callback) {callback(null, {count: count++}); },
+ destroy: function(client) {destroyCalled = client.count; },
+ validate: function(client) {validateCalled = true; return client.count != 0;},
+ max: 2,
+ idleTimeoutMillis: 100
+ };
+
+ var pool = poolModule.Pool(factory);
+ pool.acquire(function(err, obj){
+ pool.release(obj);
+ assert.equal(obj.count, 0);
+
+ pool.acquire(function(err, obj){
+ pool.release(obj);
+ assert.equal(obj.count, 1);
+ });
+ });
+ assert.equal(validateCalled, true);
+ assert.equal(destroyCalled, 0);
+ assert.equal(pool.availableObjectsCount(), 1);
+ },
+
'do schedule again if error occured when creating new Objects async': function(beforeExit){
var factory = {
name: 'test',
Something went wrong with that request. Please try again.