-
Notifications
You must be signed in to change notification settings - Fork 147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
highland doesn't handle backpressure with a mongo cursor stream #388
Comments
Actually, just noticed this seems to work with 3.0 - not sure if it's possible to backport the fix with the whole engine rewrite thing... Is 3.0 already "ready for use"? |
Is a Regardless, this is definitely a back pressure bug in highland. Even even the mongo cursor misbehaves and ignores all backpressure, it should still be held back at the source (in the stream returned by I'll try to set up a mongodb to see if I can repro this. 3.0 is ready if you're OK with depending on a github branch/commit rather than npm. We just need to add some docs and minor tests. You can consider it to be in a beta/RC stage. See #179 for the list of backwards incompatible changes. |
It's not, fails as-is. I originally had one in there since that's how we use it in production, but it's not required for the bug to occur.
I mean the second
Yep, runs indefinitely.
I think the mongo cursor should be able to handle back-pressure - it implements a streams v3 interface with
Sounds good enough for our internal use then. We don't see the same bug anymore, we're running now and we'll see if we hit another one. |
(aside: @vqvu, we could actually release a |
Well, I can't say I had a good time doing it, but I think I figured out the root cause. Basically, much of the code base assumes that various callback/handlers will not be re-entered. For example, the It's not an unreasonable assumption, since it's difficult make these things re-entrant-safe. Unfortunately, the 2.x engine is bad at guaranteeing this. There's essentially a race condition where where re-entrancy is possible under specific circumstances. When that happens, data starts being thrown away in the middle of the pipeline. That's why The 3.0 engine was written with these issues in mind, so I like to think that it's less prone to these kinds of bugs. Here's a minimal-ish test case that doesn't involve mongodb. I'll make up a PR this weekend. Edit: Added comments on what's so special about mongodb that triggers this bug. This is the reason why you can't immediately replicate the behavior in a custom var stream = _();
var i = 0;
function write() {
var cont = false;
while ((cont = stream.write(i++)) && i <= 10) {
}
if (cont) {
i++;
stream.end();
}
}
// This stream mimics the behavior of things like database
// drivers.
stream.on('drain', function () {
if (i === 0) {
// The initial read is async.
setTimeout(write, 0);
} else if (i > 0 && i < 10) {
// The driver loads data in batches, so subsequent drains
// are sync to mimic pulling from a pre-loaded buffer.
write();
} else if (i === 10) {
i++;
setTimeout(() => stream.end(), 0);
}
});
var done = false;
stream
// flatMap to disassociate from the source, since sequence
// returns a new stream not a consume stream.
.flatMap(function (x) {
return _([x]);
})
// batch(2) to get a transform that sometimes calls next
// without calling push beforehand.
.batch(2)
// Another flatMap to get an async transform.
.flatMap(function (x) {
return _(function (push) {
setTimeout(function () {
push(null, x);
push(null, _.nil);
}, 100);
});
})
.done(function () {
console.log('done');
}); @quarterto Good idea. I'll do that this weekend too. |
Now I'm not sure if this is a mongodb bug or a highland bug, but I got a repro:
Preconditions:
My collection is filled with 93 elements.
Output:
Observations:
I'll continue to try to get to the bottom of why only the mongo cursor causes this, but I thought you might have an idea why this would happen...
The text was updated successfully, but these errors were encountered: