coopernurse / node-pool

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

Process exits with waiting clients #147

Closed olalonde closed 8 years ago

olalonde commented 8 years ago
const pool = initPidPool({ max: 1 })

const handleError = (err) => {
  console.error(err)
  console.error(err.stack)
  process.exit(1)
}

for (let i = 0; i < 2; i++) {
  pool.acquire((err, pid) => {
    if (err) return handleError(err)
    console.log(pool.waitingClientsCount())
    console.log(pid)
  })
}

Prints the following and exits:

$ babel-node test/pid-pool.js
  loc:main dispense() clients=1 available=0 +0ms info
  loc:main createResource() - creating obj - count=1 min=0 max=1 +2ms verbose
  loc:apiclient:request:1 GET http://localhost/getpid +2ms
  loc:main dispense() clients=2 available=0 +1ms info
  loc:apiclient:request:1 try 1 +122ms
1
m6Myjs4ip6Hm_wLOC88ui-Dx9Ct2

Here's the code for initPidPool:

import { Pool } from 'generic-pool'

import debug from '../utils/debug'

import fetchPid from './fetch-pid'

export default ({ max = 10 } = {}) => {
  const pidExpiry = {}
  const isExpired = (pid) => Date.now() > pidExpiry[pid]

  const maxLifespanMillis = 10 * 60 * 1000 // 10min

  const pool = new Pool({
    max,
    name: 'pid',
    create: (cb) => {
      fetchPid()
        .then((pid) => {
          pidExpiry[pid] = Date.now() + maxLifespanMillis
          cb(null, pid)
        })
        .catch(cb)
    },
    validate: (pid) => !isExpired(pid),
    destroy: (pid) => { debug(`destroy pid ${pid}`) },
    min: 0,
    refreshIdle: false,
    log: debug,
  })
  return pool
}

The expected behaviour would be for the process to hang indefinitely since max is 1 and the second call to acquire should wait forever since we are not releasing the resource.

sandfox commented 8 years ago

thanks for reporting this... I'm not sure what's going on here but I have some guesses. I'll see if I can reproduce this locally and have a poke around,

olalonde commented 8 years ago

I think the issue seems to be due to the fact that both initial calls to pool.acquire are done in the same event loop. Not sure how exactly it is triggering this bug though.

sandfox commented 8 years ago

@olalonde I've got a bit lost down the rabbit hole that was dealing with the timing/order bugs in the existing version of generic-pool. In a slight acceptance of defeat I wrote v3 to use promises instead and rewrote alot of the internal logic, and I think I've made the above situation harder to get into (or at least easier to not be in!) v3 is still alpha but it's on npm npm install generic-pool@latest. There are some other additions I want to make but the current API should be what finally ships (unless it's horribly broken).