Skip to content

Commit 68819df

Browse files
author
matthew.blasius
committed
Avoid race when stream closed while fetching
1 parent e9d1872 commit 68819df

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

index.js

+3
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ QueryStream.prototype._read = function(n) {
5151
if(err) {
5252
return self.emit('error', err)
5353
}
54+
55+
if (self._closing) { return; }
56+
5457
if(!rows.length) {
5558
process.nextTick(function() {
5659
self.push(null)

test/close.js

+47
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,50 @@ helper('early close', function(client) {
3333
})
3434
})
3535
})
36+
37+
38+
helper('should not throw errors after early close', function(client) {
39+
it('can be closed early without error', function(done) {
40+
var stream = new QueryStream('SELECT * FROM generate_series(0, 2000) num');
41+
var query = client.query(stream);
42+
var fetchCount = 0;
43+
var errorCount = 0;
44+
45+
46+
function waitForErrors() {
47+
48+
setTimeout(function () {
49+
assert(errorCount === 0, 'should not throw a ton of errors');
50+
done();
51+
}, 10);
52+
}
53+
54+
// hack internal _fetch function to force query.close immediately after _fetch is called (simulating the race condition)
55+
// race condition: if close is called immediately after _fetch is called, but before results are returned, errors are thrown
56+
// when the fetch results are pushed to the readable stream after its already closed.
57+
query._fetch = (function (_fetch) {
58+
return function () {
59+
60+
// wait for the second fetch. closing immediately after the first fetch throws an entirely different error :(
61+
if (fetchCount++ === 0) {
62+
return _fetch.apply(this, arguments);
63+
}
64+
65+
var results = _fetch.apply(this, arguments);
66+
67+
query.close();
68+
waitForErrors();
69+
70+
query._fetch = _fetch; // we're done with our hack, so restore the original _fetch function.
71+
72+
return results;
73+
}
74+
}(query._fetch));
75+
76+
query.on('error', function () { errorCount++; });
77+
78+
query.on('readable', function () {
79+
query.read();
80+
});
81+
});
82+
});

0 commit comments

Comments
 (0)