{"id":17331,"library":"pool2","title":"Pool2","description":"Pool2 is a generic resource pooling library for Node.js, designed to efficiently manage expensive, reusable resources like database connections or network sockets. It provides a configurable framework for acquiring, releasing, disposing, and destroying resources, incorporating essential features such as minimum and maximum pool sizes, idle timeouts, request queuing, and health checks (ping functions). Key differentiators include its robust handling of resource lifecycle events and explicit timeouts for acquire and dispose operations, which helps prevent resource leaks and ensure application stability. The package is currently at version 1.4.1. While a specific release cadence isn't defined, the documentation indicates it's a mature and stable solution for resource management, offering fine-grained control over resource behavior and pooling strategies.","status":"active","version":"1.4.1","language":"javascript","source_language":"en","source_url":"ssh://git@github.com/myndzi/pool2","tags":["javascript","database","pool","cluster"],"install":[{"cmd":"npm install pool2","lang":"bash","label":"npm"},{"cmd":"yarn add pool2","lang":"bash","label":"yarn"},{"cmd":"pnpm add pool2","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"Pool2 v1.x is primarily a CommonJS module. Direct ES Module 'import' syntax is not officially supported without a transpiler or a CommonJS wrapper.","wrong":"import Pool from 'pool2';","symbol":"Pool","correct":"const Pool = require('pool2');"}],"quickstart":{"code":"const Pool = require('pool2');\n\n// Simulate a resource that takes time to acquire and needs disposal\nlet resourceCounter = 0;\n\nfunction createResource(id) {\n  return {\n    id: id,\n    status: 'open',\n    connect: () => new Promise(resolve => setTimeout(() => {\n      console.log(`Resource ${id} connected.`);\n      resolve();\n    }, 100)),\n    close: () => new Promise(resolve => setTimeout(() => {\n      console.log(`Resource ${id} closed.`);\n      resolve();\n    }, 50)),\n    destroy: () => {\n      console.log(`Resource ${id} forcibly destroyed.`);\n    }\n  };\n}\n\nconst pool = new Pool({\n  acquire: function (cb) {\n    const id = ++resourceCounter;\n    const rsrc = createResource(id);\n    rsrc.connect()\n      .then(() => cb(null, rsrc))\n      .catch(err => cb(err));\n  },\n  acquireTimeout: 5000,\n  dispose: function (rsrc, cb) {\n    rsrc.close()\n      .then(() => cb())\n      .catch(err => cb(err));\n  },\n  disposeTimeout: 2000,\n  destroy: function (rsrc) {\n    if (rsrc && rsrc.status === 'open') {\n      rsrc.destroy();\n    }\n  },\n  ping: function (rsrc, cb) {\n    // Simple ping, assume resource is always alive for this example\n    cb();\n  },\n  min: 1,\n  max: 3,\n  idleTimeout: 3000,\n  syncInterval: 1000\n});\n\nasync function usePool() {\n  console.log('Acquiring resource...');\n  let resource;\n  try {\n    resource = await new Promise((resolve, reject) => {\n      pool.acquire((err, r) => {\n        if (err) return reject(err);\n        resolve(r);\n      });\n    });\n    console.log(`Successfully acquired resource ${resource.id}. Doing work...`);\n    await new Promise(resolve => setTimeout(resolve, 500)); // Simulate work\n  } catch (err) {\n    console.error('Failed to acquire resource:', err.message);\n    return;\n  } finally {\n    if (resource) {\n      console.log(`Releasing resource ${resource.id}.`);\n      pool.release(resource);\n    }\n  }\n  console.log('Current pool stats:', pool.stats());\n}\n\n(async () => {\n  await usePool();\n  await usePool();\n  await usePool();\n\n  console.log('Ending pool in 5 seconds...');\n  setTimeout(() => {\n    pool.end((errs) => {\n      if (errs && errs.length > 0) {\n        console.error('Errors during pool end:', errs);\n      } else {\n        console.log('Pool ended gracefully.');\n      }\n    });\n  }, 5000);\n})();","lang":"javascript","description":"Demonstrates the basic creation of a resource pool, acquiring and releasing resources, and observing pool statistics. It includes custom acquire/dispose/destroy functions with asynchronous operations and pool shutdown."},"warnings":[{"fix":"Implement connection-level timeouts within your `acquire` function's resource creation logic. For instance, if connecting to a database, ensure the database driver's connection timeout is set and that a timeout error from the driver is passed to the `acquire` callback to properly notify `pool2`.","message":"The `acquireTimeout` only dictates how long `pool2` waits for the `acquire` function to *finish* its callback. If the underlying resource acquisition (e.g., database connection) takes longer than `acquireTimeout` but eventually succeeds, `pool2` will have moved on, potentially leading to unmanaged 'in-flight' resources that exceed `max` capacity. It's crucial for the `acquire` function itself to implement and handle its own timeouts and clean up if it exceeds an internal limit.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure your `dispose` function thoroughly attempts to close the resource and handles potential errors gracefully. Log any `dispose` failures prominently to identify and debug resource leakage issues promptly. Consider a more aggressive cleanup in the `destroy` function if `dispose` fails.","message":"Failures in the `dispose` function, even if `disposeTimeout` is set, will still remove the resource from the pool. However, if the underlying resource's graceful closure fails, it may leave dangling sockets or open handles, preventing a graceful application exit or causing resource leaks outside of `pool2`'s control.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Keep `destroy` logic idempotent and non-blocking if possible. Critical cleanup that *must* complete should ideally be handled within a robust `dispose` function, or with external monitoring for resources that `destroy` attempts to clean up.","message":"The `destroy` function is 'fire-and-forget' and does not accept a callback. This means `pool2` does not wait for or guarantee the completion of the `destroy` logic. It's intended as a last-resort cleanup.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Carefully balance `min` and `max` based on your application's typical and peak load. Set `idleTimeout` to reclaim unused resources, but ensure it's shorter than any upstream server-side timeouts (e.g., database `wait_timeout`) to prevent stale connections. Monitor pool metrics (`pool.stats()`) in production to fine-tune these values.","message":"Incorrectly configuring `min` and `max` pool sizes alongside `idleTimeout` and `syncInterval` can lead to unexpected pool behavior, such as premature resource destruction or excessive resource creation during low load, or connection pool exhaustion under high load if not sized correctly relative to the application's demands and database capacity.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Increase `acquireTimeout` if the resource truly takes longer to provision, or set `requestTimeout` if waiting for an available resource. More importantly, check if the underlying resource acquisition in your `acquire` function has its own timeouts and handles them by reporting failure to `pool2`'s callback. Also verify `max` pool size and `maxRequests` are adequate for your load.","cause":"The `acquire` function took longer than `acquireTimeout` to invoke its callback, or no resources were available within the `requestTimeout` and `maxRequests` limits. This does not necessarily mean the resource failed to connect, only that `pool2` stopped waiting.","error":"Error: Acquire Timeout Exceeded"},{"fix":"Thoroughly review the `dispose` function implementation to ensure all necessary steps are taken to gracefully close the resource. Add logging for `dispose` failures to quickly identify and troubleshoot issues related to resource leakage. Consider integrating a linter or static analysis tool to catch unhandled promises or forgotten callbacks.","cause":"The `dispose` function failed to properly close an underlying resource (e.g., a database connection), leading to a resource leak. While `pool2` removes the resource from its internal tracking, the external resource remains open and unmanaged.","error":"Application hangs or crashes unexpectedly due to too many open file descriptors or 'Socket already closed' errors."}],"ecosystem":"npm","meta_description":null}