Skip to content

Commit b011bc1

Browse files
authored
Merge pull request #313 from lutovich/1.5-pool-fix
Fixed timeout when acquiring connection from pool
2 parents 47f5875 + d992409 commit b011bc1

File tree

3 files changed

+60
-5
lines changed

3 files changed

+60
-5
lines changed

src/v1/internal/pool.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,10 @@ class Pool {
162162
// check if there are any pending requests
163163
const requests = this._acquireRequests[key];
164164
if (requests) {
165-
var pending = requests.shift();
165+
const pending = requests.shift();
166166

167167
if (pending) {
168-
var resource = this._acquire(key);
168+
const resource = this._acquire(key);
169169
if (resource) {
170170
pending.resolve(resource);
171171

src/v1/internal/util.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* limitations under the License.
1818
*/
1919

20-
import { newError } from "../error";
20+
import {newError} from '../error';
2121

2222
const ENCRYPTION_ON = "ENCRYPTION_ON";
2323
const ENCRYPTION_OFF = "ENCRYPTION_OFF";
@@ -125,6 +125,8 @@ function trimAndVerify(string, name, url) {
125125
}
126126

127127
function promiseOrTimeout(timeout, otherPromise, onTimeout) {
128+
let resultPromise = null;
129+
128130
const timeoutPromise = new Promise((resolve, reject) => {
129131
const id = setTimeout(() => {
130132
if (onTimeout && typeof onTimeout === 'function') {
@@ -134,10 +136,22 @@ function promiseOrTimeout(timeout, otherPromise, onTimeout) {
134136
reject(newError(`Operation timed out in ${timeout} ms.`));
135137
}, timeout);
136138

137-
otherPromise.then(() => clearTimeout(id), () => clearTimeout(id));
139+
// this "executor" function is executed immediately, even before the Promise constructor returns
140+
// thus it's safe to initialize resultPromise variable here, where timeout id variable is accessible
141+
resultPromise = otherPromise.then(result => {
142+
clearTimeout(id);
143+
return result;
144+
}).catch(error => {
145+
clearTimeout(id);
146+
throw error;
147+
});
138148
});
139149

140-
return Promise.race([ otherPromise, timeoutPromise ]);
150+
if (resultPromise == null) {
151+
throw new Error('Result promise not initialized');
152+
}
153+
154+
return Promise.race([resultPromise, timeoutPromise]);
141155
}
142156

143157
export {

test/internal/util.test.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,47 @@ describe('util', () => {
204204
});
205205
});
206206

207+
it('should not trigger both promise and timeout', done => {
208+
const timeout = 500;
209+
210+
let timeoutFired = false;
211+
let result = null;
212+
let error = null;
213+
214+
const resultPromise = util.promiseOrTimeout(
215+
timeout,
216+
new Promise(resolve => {
217+
setTimeout(() => {
218+
resolve(42);
219+
}, timeout);
220+
}),
221+
() => {
222+
timeoutFired = true;
223+
}
224+
);
225+
226+
resultPromise.then(r => {
227+
result = r;
228+
}).catch(e => {
229+
error = e;
230+
});
231+
232+
setTimeout(() => {
233+
if (timeoutFired) {
234+
// timeout fired - result should not be set, error should be set
235+
expect(result).toBeNull();
236+
expect(error).not.toBeNull();
237+
expect(error.message).toEqual(`Operation timed out in ${timeout} ms.`);
238+
done();
239+
} else {
240+
// timeout did not fire - result should be set, error should not be set
241+
expect(result).toEqual(42);
242+
expect(error).toBeNull();
243+
done();
244+
}
245+
}, timeout * 2);
246+
});
247+
207248
function verifyValidString(str) {
208249
expect(util.assertString(str, 'Test string')).toBe(str);
209250
}

0 commit comments

Comments
 (0)