coopernurse / node-pool

Generic resource pooling for node.js
2.37k stars 259 forks source link

testOnBorrow not always firing #233

Open bforbis opened 6 years ago

bforbis commented 6 years ago

I am trying to understand how the pool returns resources. Using the following test, I can see a few weird behaviors:

  1. Setting testOnBorrow = true does not always run the validate function. It seems like this might be a race condition between starting the pool and acquiring the first resource, since pool.start does not return a promise that can be waited on. This can be fixed by adding an arbitrary delay before the first pool.acquire call. I feel like it would be better if I can just wait on pool.start()
  2. number of resources in the pool can go over the configured max. This can be shown here in the console out. The object ID goes up to 2, even though I've set the max to 1.
    
    'use strict';
    /* eslint-disable */

const genericPool = require('generic-pool');

let id = 1; const pool = genericPool.createPool({ create: async () => { const obj = { id: id++ }; console.log(Creating object ${JSON.stringify(obj)}); return obj; }, validate: async (obj) => { console.log(VALIDATING OBJECT ${JSON.stringify(obj)}); return true; }, destroy: async (obj) => { console.log(Destroying object ${JSON.stringify(obj)}); }, }, { testOnBorrow: true, autostart: false, min: 1, max: 1, fifo: false, });

async function main() { console.log('Starting pool');

// Pool.start has nothing to wait on await pool.start();

// Commenting out set timeout will make it so // the first object is not validated on borrow // setTimeout(async () => { let o; console.log('1st test, acquiring from pool'); o = await pool.acquire(); console.log(1st test, retrieved id ${o.id});

console.log(`1st test, releasing to pool id ${o.id}`);
await pool.release(o);

console.log('2nd test, acquiring from pool');
o = await pool.acquire();
console.log(`2nd test, retrieved id ${o.id}`);

console.log(`2nd test, releasing to pool id ${o.id}`);
await pool.release(o);

console.log('Closing pool');
await pool.drain();
await pool.clear();

// }, 1); }

main();


Console output:

Starting pool Creating object {"id":1} 1st test, acquiring from pool Creating object {"id":2} 1st test, retrieved id 1 1st test, releasing to pool id 1 2nd test, acquiring from pool VALIDATING OBJECT {"id":1} 2nd test, retrieved id 1 2nd test, releasing to pool id 1 Closing pool Destroying object {"id":1} Destroying object {"id":2}

sandfox commented 6 years ago

thanks for reporting this @bforbis, I highly suspect you are onto something here! I'll try and have a look in the next few days and see what I can reproduce/understand. There is a fair bit of messy logic around pool startup that has the potential for this sort of problem.