From 7ab071542d317c2ce3eefda09915a017623c0578 Mon Sep 17 00:00:00 2001 From: Joel Brandt Date: Wed, 6 Jul 2022 07:41:22 -0700 Subject: [PATCH 1/2] add unit test for sync .use --- test/generic-pool-test.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/generic-pool-test.js b/test/generic-pool-test.js index baaddfbb..0b262c28 100644 --- a/test/generic-pool-test.js +++ b/test/generic-pool-test.js @@ -790,6 +790,34 @@ tap.test("use method should resolve after fn promise is resolved", function(t) { }); }); +tap.test("use method should handle synchronous work functions", function(t) { + const pool = createPool(new ResourceFactory()); + const initialBorrowed = pool.borrowed; + const result = pool.use(resource => { + t.equal(initialBorrowed + 1, pool.borrowed); + return resource.id; + }); + result.then(val => { + t.equal(val, 0); + t.equal(initialBorrowed, pool.borrowed); + t.end(); + }); +}); + +tap.test("use method should handle synchronous throws", function(t) { + const pool = createPool(new ResourceFactory()); + const initialBorrowed = pool.borrowed; + const result = pool.use(resource => { + t.equal(initialBorrowed + 1, pool.borrowed); + throw new Error("expected"); + }); + result.catch(e => { + t.equal(initialBorrowed, pool.borrowed); + t.equal(e.message, "expected"); + t.end(); + }); +}); + tap.test("evictor should not run when softIdleTimeoutMillis is -1", function( t ) { From 55f50b1d54e6da490329043beddf7e5c83d2c633 Mon Sep 17 00:00:00 2001 From: Joel Brandt Date: Wed, 6 Jul 2022 07:41:37 -0700 Subject: [PATCH 2/2] make .use work with sync functions --- lib/Pool.js | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/Pool.js b/lib/Pool.js index 0a006dda..94ed1549 100644 --- a/lib/Pool.js +++ b/lib/Pool.js @@ -471,13 +471,31 @@ class Pool extends EventEmitter { } /** - * [use method, aquires a resource, passes the resource to a user supplied function and releases it] - * @param {Function} fn [a function that accepts a resource and returns a promise that resolves/rejects once it has finished using the resource] + * [use method, acquires a resource, passes the resource to a user supplied function and releases it] + * @param {Function} fn [a function that accepts a resource. If the function returns a Promise (anything then-able), the resource is released when the Promise resolves/rejects. Otherwise, the resource is released immediately after execution.] * @return {Promise} [resolves once the resource is released to the pool] */ use(fn, priority) { return this.acquire(priority).then(resource => { - return fn(resource).then( + let wrappedFnResult; + try { + const fnResult = fn(resource); + // if fnResult is not then-able, wrap it in a resolved Promise. + if ( + typeof fnResult !== "object" || + fnResult === null || + !("then" in fnResult) + ) { + wrappedFnResult = Promise.resolve(fnResult); + } else { + wrappedFnResult = fnResult; + } + } catch (e) { + // if fn throws synchronously, turn the exception into a rejected Promise. + wrappedFnResult = Promise.reject(e); + } + + return wrappedFnResult.then( result => { this.release(resource); return result;