Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add error handler option and the ability to grow and shrink the pool maximum size at runtime #43

Open
wants to merge 6 commits into from

6 participants

@oddmarthon-lende

Don't know if this is something you would want, error handling can be done without support for it in the pool object.

oddmarthon-lende added some commits
@oddmarthon-lende oddmarthon-lende Handle error events
Listen to error events on resources that inherits EventEmitter and add optional factory.error
If no factory.error handler exists obj will be destroyed automagically if an error event is catched.
dc20f69
@oddmarthon-lende oddmarthon-lende Fix error handler for events and add grow() and shrink() e4ac4d4
@oddmarthon-lende oddmarthon-lende Fix crash if no callback and error 94ae5e6
@travisbot

This pull request passes (merged c894fce7 into 7d8e79a).

@travisbot

This pull request passes (merged 42d5010 into 2de03be).

@travisbot

This pull request passes (merged 9e536bd into 69180f3).

@imkira

Hi Marthon, thank you for your pull request.
It is almost working for me, except I had to change the following line in generic-pool/lib/generic-pool.js:

131     factory.error = function(err, obj) {
132       log("error() - unhandled error ["+err.message+"] - destroying obj", 'verbose');
133       this.destroy(obj); // --> factory.destroy(obj);                                                                                                                                    
134     }.bind(this);
@aahoughton

This would be helpful (the grow / shrink options). Any chance of getting this merged in?

@jmdobry

:+1: for grow/shrink getting merged in. Really need this.

@sandfox
Collaborator

This looks good, but could it be split into separate PR's. One for the grow/shrink and one for error handling. grow/shrink is definately shippable, but unsure about putting error handling into the pool, rather than making it easier to access/handle outside the pool.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 2, 2012
  1. @oddmarthon-lende

    Handle error events

    oddmarthon-lende authored
    Listen to error events on resources that inherits EventEmitter and add optional factory.error
    If no factory.error handler exists obj will be destroyed automagically if an error event is catched.
Commits on Aug 3, 2012
  1. @oddmarthon-lende
Commits on Aug 13, 2012
  1. @oddmarthon-lende
Commits on Aug 29, 2012
  1. @oddmarthon-lende

    Some minor changes and additions

    Odd Marthon Lende authored oddmarthon-lende committed
Commits on Aug 30, 2012
  1. @oddmarthon-lende
Commits on Sep 10, 2012
  1. @oddmarthon-lende
This page is out of date. Refresh to see the latest.
Showing with 128 additions and 3 deletions.
  1. +18 −0 README.md
  2. +65 −1 lib/generic-pool.js
  3. +45 −2 test/generic-pool.test.js
View
18 README.md
@@ -179,6 +179,9 @@ If you do this, your node process will exit gracefully.
- log level ('verbose', 'info', 'warn', 'error')
Else if log is true, verbose log info will be sent to console.log()
Else internal log messages be ignored (this is the default)
+ error : function that is called when an error event is emitted by a resource -
+ If resources emits events and an error event is received and this is not set the resource will be destroyed.
+
## Priority Queueing
@@ -277,6 +280,21 @@ The following functions will let you get information about the pool:
// returns number of callers waiting to acquire a resource
pool.waitingClientsCount()
+## Pool grow and shrink
+
+The following functions allows you the adjust the maximum pool dynamically at run time:
+
+ // Grows the pool max size by amount
+ // If no parameter is given amount = 1
+ // returns new max size
+ pool.grow(amount)
+
+ // Shrinks the pool max size by amount
+ // If no parameter is given amount = 1
+ // Never exceeds minimum size, then max === min
+ // returns new max size
+ pool.shrink(amount)
+
## Run Tests
View
66 lib/generic-pool.js
@@ -1,3 +1,4 @@
+var EventEmitter = require('events').EventEmitter;
var PriorityQueue = function(size) {
var me = {}, slots, i, total = null;
@@ -107,6 +108,7 @@ exports.Pool = function (factory) {
// Prepare a logger function.
log = factory.log ?
(function (str, level) {
+ str = ' ['+(factory.name||'')+'] ' + str;
if (typeof factory.log === 'function') {
factory.log(str, level);
}
@@ -122,10 +124,57 @@ exports.Pool = function (factory) {
factory.max = Math.max(isNaN(factory.max) ? 1 : factory.max, 1);
factory.min = Math.min(isNaN(factory.min) ? 0 : factory.min, factory.max-1);
+
+ if(typeof factory.error === 'function')
+ factory.error = factory.error.bind(me);
+ else
+ factory.error = function(err, obj) {
+ log("error() - unhandled error ["+err.message+"] - destroying obj", 'verbose');
+ me.destroy(obj);
+ };
///////////////
/**
+ * Grow the pool
+ * @param {Number} amount
+ */
+
+ me.grow = function(amount) {
+
+ amount = parseInt(amount, 10);
+ amount = isNaN(amount) ? 1 : amount;
+
+ factory.max += amount;
+
+ log("grow() - amount ["+amount+"] - new size ["+factory.max+"]", 'verbose');
+
+ return factory.max;
+
+ };
+
+ /**
+ * Shrink the pool
+ * @param {Number} amount
+ */
+
+ me.shrink = function(amount) {
+
+ amount = parseInt(amount, 10);
+ amount = isNaN(amount) ? 1 : amount;
+
+ if( (factory.max - amount) < factory.min)
+ factory.max = factory.min;
+ else
+ factory.max -= amount;
+
+ log("shrink() - amount [-"+amount+"] - new size ["+factory.max+"]", 'verbose');
+
+ return factory.max;
+
+ };
+
+ /**
* Request the client to be destroyed. The factory's destroy handler
* will also be called.
*
@@ -134,11 +183,14 @@ exports.Pool = function (factory) {
* @param {Object} obj
* The acquired item to be destoyed.
*/
+
me.destroy = function(obj) {
count -= 1;
availableObjects = availableObjects.filter(function(objWithTimeout) {
return (objWithTimeout.obj !== obj);
});
+ if(obj instanceof EventEmitter && typeof obj.__pool_error_handler === 'function')
+ obj.removeListener('error', obj.__pool_error_handler);
factory.destroy(obj);
ensureMinimum();
@@ -253,9 +305,21 @@ exports.Pool = function (factory) {
err = (arguments[0] instanceof Error) ? arguments[0] : null;
obj = (arguments[0] instanceof Error) ? null : arguments[0];
}
+ if(obj instanceof EventEmitter && !obj.listeners('error').length) {
+ if(typeof factory.error === 'function') {
+ log("createResource() - creating error handler", 'verbose');
+ obj.__pool_error_handler = function(err) {
+ factory.error(err, obj);
+ };
+ obj.on('error', obj.__pool_error_handler);
+ }
+ }
if (err) {
count -= 1;
- clientCb(err, obj);
+ if(clientCb)
+ clientCb(err, obj);
+ else
+ factory.error(err, obj);
} else {
if (clientCb) {
clientCb(err, obj);
View
47 test/generic-pool.test.js
@@ -1,5 +1,6 @@
var assert = require('assert');
var poolModule = require('..');
+var EventEmitter = require('events').EventEmitter;
module.exports = {
@@ -258,6 +259,48 @@ module.exports = {
});
},
+ 'handle runtime errors' : function (beforeExit) {
+ var count = 0,
+ errors = 0;
+ var pool = poolModule.Pool({
+ name : 'test7',
+ create : function(callback) {
+
+ var emitter = function() {
+
+ if(count % 2)
+ setTimeout(function() {
+ this.emit('error', new Error(count))
+ }.bind(this), 0);
+
+ count++;
+
+ };
+ emitter.prototype.__proto__ = EventEmitter.prototype;
+ callback(null, new emitter());
+
+ },
+ destroy : function(client) {},
+ error : function(error, client) {
+ assert.ok(count % 2);
+ errors++;
+ },
+ max : 5,
+ idleTimeoutMillis : 1000
+ });
+
+ for (var i = 0; i < 5; i++) {
+ pool.acquire(function(err, client) {
+ assert.ok(!(err instanceof Error));
+ assert.ok(!!client);
+ });
+ }
+
+ beforeExit(function() {
+ assert.equal(2, errors);
+ });
+ },
+
'pooled decorator should acquire and release' : function (beforeExit) {
var assertion_count = 0;
var destroyed_count = 0;
@@ -483,8 +526,8 @@ module.exports = {
pool.acquire(function(err, obj){
if (err) {throw err;}
- assert.equal(logmessages.verbose[0], 'createResource() - creating obj - count=1 min=0 max=2');
- assert.equal(logmessages.info[0], 'dispense() clients=1 available=0');
+ assert.equal(logmessages.verbose[0], ' [test1] createResource() - creating obj - count=1 min=0 max=2');
+ assert.equal(logmessages.info[0], ' [test1] dispense() clients=1 available=0');
logmessages.info = [];
logmessages.verbose = [];
pool2.borrow(function(err, obj){
Something went wrong with that request. Please try again.