diff --git a/lib/Pool.js b/lib/Pool.js index 0a006dd..94ed154 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; diff --git a/test/generic-pool-test.js b/test/generic-pool-test.js index baaddfb..0b262c2 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 ) {