generic-pool
Advanced tools
Comparing version 1.0.10 to 1.0.11
@@ -351,2 +351,40 @@ var PriorityQueue = function(size) { | ||
/** | ||
* Decorates a function to use a acquired client from the object pool when called. | ||
* | ||
* @param {Function} decorated | ||
* The decorated function, accepting a client as the first argument and | ||
* (optionally) a callback as the final argument. | ||
* | ||
* @param {Number} priority | ||
* Optional. Integer between 0 and (priorityRange - 1). Specifies the priority | ||
* of the caller if there are no available resources. Lower numbers mean higher | ||
* priority. | ||
*/ | ||
me.pooled = function(decorated, priority) { | ||
return function() { | ||
var callerArgs = arguments; | ||
var callerCallback = callerArgs[callerArgs.length - 1]; | ||
var callerHasCallback = typeof callerCallback === 'function'; | ||
me.acquire(function(err, client) { | ||
if(err) { | ||
if(callerHasCallback) { | ||
callerCallback(err); | ||
} | ||
return; | ||
} | ||
var args = [client].concat(Array.prototype.slice.call(callerArgs, 0, callerHasCallback ? -1 : undefined)); | ||
args.push(function() { | ||
me.release(client); | ||
if(callerHasCallback) { | ||
callerCallback.apply(null, arguments); | ||
} | ||
}); | ||
decorated.apply(null, args); | ||
}, priority); | ||
}; | ||
}; | ||
me.getPoolSize = function() { | ||
@@ -368,3 +406,4 @@ return count; | ||
return me; | ||
}; |
{ | ||
"name": "generic-pool", | ||
"description": "Generic resource pooling for Node.JS", | ||
"version": "1.0.10", | ||
"version": "1.0.11", | ||
"author": "James Cooper <james@bitmechanic.com>", | ||
@@ -6,0 +6,0 @@ "contributors": [ |
@@ -13,2 +13,5 @@ | ||
1.0.11 - June 17 2012 | ||
- Merged #36 ("pooled" method to perform function decoration for pooled methods - contributed by cosbynator) | ||
1.0.10 - May 3 2012 | ||
@@ -114,3 +117,3 @@ - Merged #35 (Remove client from availbleObjects on destroy(client) - contributed by blax) | ||
The pool now supports optional priority queueing. This becomes relevant when no resources | ||
are available and the caller has to wait. acquire() accepts an optional priority int which | ||
are available and the caller has to wait. `acquire()` accepts an optional priority int which | ||
specifies the caller's relative position in the queue. | ||
@@ -163,2 +166,31 @@ | ||
## Pooled function decoration | ||
To transparently handle object acquisition for a function, | ||
one can use `pooled()`: | ||
var privateFn, publicFn; | ||
publicFn = pool.pooled(privateFn = function(client, arg, cb) { | ||
// Do something with the client and arg. Client is auto-released when cb is called | ||
cb(null, arg); | ||
}); | ||
Keeping both private and public versions of each function allows for pooled | ||
functions to call other pooled functions with the same member. This is a handy | ||
pattern for database transactions: | ||
var privateTop, privateBottom, publicTop, publicBottom; | ||
publicBottom = pool.pooled(privateBottom = function(client, arg, cb) { | ||
//Use client, assumed auto-release | ||
}); | ||
publicTop = pool.pooled(privateTop = function(client, cb) { | ||
// e.g., open a database transaction | ||
privateBottom(client, "arg", function(err, retVal) { | ||
if(err) { return cb(err); } | ||
// e.g., close a transaction | ||
cb(); | ||
}); | ||
}); | ||
## Pool info | ||
@@ -191,3 +223,3 @@ | ||
Copyright (c) 2010-2011 James Cooper <james@bitmechanic.com> | ||
Copyright (c) 2010-2012 James Cooper <james@bitmechanic.com> | ||
@@ -194,0 +226,0 @@ Permission is hereby granted, free of charge, to any person obtaining |
@@ -198,2 +198,113 @@ var assert = require('assert'); | ||
'pooled decorator should acquire and release' : function (beforeExit) { | ||
var assertion_count = 0; | ||
var destroyed_count = 0; | ||
var pool = poolModule.Pool({ | ||
name : 'test1', | ||
create : function(callback) { callback({id: Math.floor(Math.random()*1000)}); }, | ||
destroy : function(client) { destroyed_count += 1; }, | ||
max : 1, | ||
idleTimeoutMillis : 100 | ||
}); | ||
var pooledFn = pool.pooled(function(client, cb) { | ||
assert.equal(typeof client.id, 'number'); | ||
assert.equal(pool.getPoolSize(), 1); | ||
assertion_count += 2; | ||
cb(); | ||
}); | ||
assert.equal(pool.getPoolSize(), 0); | ||
assertion_count += 1; | ||
pooledFn(function(err) { | ||
if (err) { throw err; } | ||
assert.ok(true); | ||
assertion_count += 1; | ||
}); | ||
beforeExit(function() { | ||
assert.equal(assertion_count, 4); | ||
assert.equal(destroyed_count, 1); | ||
}); | ||
}, | ||
'pooled decorator should pass arguments and return values' : function(beforeExit) { | ||
var assertion_count = 0; | ||
var pool = poolModule.Pool({ | ||
name : 'test1', | ||
create : function(callback) { callback({id: Math.floor(Math.random()*1000)}); }, | ||
destroy : function(client) { }, | ||
max : 1, | ||
idleTimeoutMillis : 100 | ||
}); | ||
var pooledFn = pool.pooled(function(client, arg1, arg2, cb) { | ||
assert.equal(arg1, "First argument"); | ||
assert.equal(arg2, "Second argument"); | ||
assertion_count += 2; | ||
cb(null, "First return", "Second return"); | ||
}); | ||
pooledFn("First argument", "Second argument", function(err, retVal1, retVal2) { | ||
if(err) { throw err; } | ||
assert.equal(retVal1, "First return"); | ||
assert.equal(retVal2, "Second return"); | ||
assertion_count += 2; | ||
}); | ||
beforeExit(function() { | ||
assert.equal(assertion_count, 4); | ||
}); | ||
}, | ||
'pooled decorator should allow undefined callback' : function(beforeExit) { | ||
var assertion_count = 0; | ||
var pool = poolModule.Pool({ | ||
name : 'test1', | ||
create : function(callback) { callback({id: Math.floor(Math.random()*1000)}); }, | ||
destroy : function(client) { }, | ||
max : 1, | ||
idleTimeoutMillis : 100 | ||
}); | ||
var pooledFn = pool.pooled(function(client, arg, cb) { | ||
assert.equal(arg, "Arg!"); | ||
assertion_count += 1; | ||
cb(); | ||
}); | ||
pooledFn("Arg!"); | ||
beforeExit(function() { | ||
assert.equal(pool.getPoolSize(), 0); | ||
assert.equal(assertion_count, 1); | ||
}); | ||
}, | ||
'pooled decorator should forward pool errors' : function(beforeExit) { | ||
var assertion_count = 0; | ||
var pool = poolModule.Pool({ | ||
name : 'test1', | ||
create : function(callback) { callback(new Error('Pool error')); }, | ||
destroy : function(client) { }, | ||
max : 1, | ||
idleTimeoutMillis : 100 | ||
}); | ||
var pooledFn = pool.pooled(function(cb) { | ||
assert.ok(false, "Pooled function shouldn't be called due to a pool error"); | ||
}); | ||
pooledFn(function(err, obj) { | ||
assert.equal(err.message, 'Pool error'); | ||
assertion_count += 1; | ||
}); | ||
beforeExit(function() { | ||
assert.equal(assertion_count, 1); | ||
}); | ||
}, | ||
'getPoolSize' : function (beforeExit) { | ||
@@ -200,0 +311,0 @@ var assertion_count = 0; |
37155
756
240