-
Notifications
You must be signed in to change notification settings - Fork 228
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
proper way to clone a stream? #202
Comments
Could you provide an example that reproduces this error? My guess is that if your streams ends up in paused mode you probably aren't draining your cloning stream. |
Let's just understand what Reading the original, it seems you want to pipe the same source stream to two destinations, and you want backpressure handled. Is it correct? Would you prefer the conversation to continue here or there? Anyway, this is the example ported from coffee-script: var fs = require('fs')
var stream = require('stream')
var contents = fs.createReadStream('./bigfile') // greater than 65KB
var stream1 = contents.pipe(new stream.PassThrough())
var stream2 = contents.pipe(new stream.PassThrough())
stream1.on('data', function (data) { console.log('s1', data.length) })
stream1.on('end', function () {
stream2.on('data', function (data) { console.log('s2', data.length) })
}) which is broken on node v0.10 and v0.12, but it is working as expected on node v4 and v5 (streams 3). |
@mcollina oh, that's interesting. I didn't realize streams 3 changed (fixed?) the way this was handled. Specifically, we are cloning a Someone could do something like: var file = new Vinyl({
contents: fs.createReadStream('./somefile').pipe(gzip())
});
var file2 = file.clone(); Currently we are piping that same source to 2 destinations but the original reporter of the issue says the If this is fixed in streams 3, is there a way for us to wrap or convert a stream created by no 0.10 or 0.12 into streams 3? We use through2 and/or readable-stream (although they need to be update) almost everywhere except the |
So, this works in node v4 and v5 (not in 0.10 or 0.12): var Vinyl = require('vinyl')
var fs = require('fs')
var gzip = require('zlib').createGzip
var file = new Vinyl({
contents: fs.createReadStream('../node.tar')
});
var file2 = file.clone();
file2.pipe(gzip()).pipe(fs.createWriteStream('./cloned')) But this don't: var Vinyl = require('vinyl')
var fs = require('fs')
var gzip = require('zlib').createGzip
var file = new Vinyl({
contents: fs.createReadStream('../node.tar').pipe(gzip())
});
var file2 = file.clone();
file2.pipe(fs.createWriteStream('./cloned'))
// uncommenting the following line makes everything work
// file.pipe(fs.createWriteStream('./other')) I would also note that by not piping The following works everywhere: var through2 = require('through2')
var Vinyl = require('vinyl')
var fs = require('fs')
var gzip = require('zlib').createGzip
var count = 0
var file = new Vinyl({
contents: fs.createReadStream('../node.tar').pipe(through2(function (buf, enc, cb) {
count += buf.length
this.push(buf)
cb()
}))
});
var file2 = file.clone();
file2.pipe(fs.createWriteStream('./cloned2')) It seems this is a bug in BTW, this issue is extremely interesting. (I think Vinyl should depend on readable-stream to normalize all the behavior regarding streams anyway). |
Yea and that's the whole thing leading to this bugs. I can't get why not just remove it?
Absolutely.
In your last example you are not using |
@mcollina thanks for all your advice on this. |
In the context of these Vinyl objects being passed through the vinyl-fs stream, and the |
The example being: 'use strict';
var vfs = require('vinyl-fs');
var through = require('through2');
vfs.src('../node.tar', { buffer: false })
.pipe(through.obj(function(file, enc, next) {
var clone = file.clone();
clone.stem = 'cloned';
this.push(clone);
next(null, file);
}))
.pipe(vfs.dest('./dest'))
.on('end', function() {
console.log('done!');
}); If you use the latest |
I don't know what means "it works fine" here, because on node 5 and if L70 is removed, it only populates one file (because there are created two files in And |
@tunnckoCore yep, you are seeing the same thing as me. Line 70 has to stay. |
It seems using var contents;
if (this.isStream()) {
contents = this.contents.pipe(through2())
this.contents = this.contents.pipe(through2())
} |
Folks, it's really hard to solve this problem from vinyl point of view. If it's a problem in one (or more) versions of streams, or in another submodules, we need to tackle those separately. Even in they are specific to a node version lines. Using vinyl as an example makes things way more complicated for us to help you (we need to dig into Vinyl code) and there is the chance that the actual way you are using streams might not be the correct way to use them. All of this looks like heisenbugs. @tunnckoCore this is the example about gzip that I was talking about: var Vinyl = require('vinyl')
var fs = require('fs')
var gzip = require('zlib').createGzip
var file = new Vinyl({
contents: fs.createReadStream('../node.tar').pipe(gzip())
});
var file2 = file.clone();
file2.pipe(fs.createWriteStream('./cloned')) @phated is the orignal problem only related to gzip in node v4+/streams 3? Or is there something else this issue manifest itself using node v4+ (streams 3). If that is the case, the bug its on the gzip side rather than the vinyl or stream. @phated regarding the "double through", I still think it's a really bad idea, because you are possibly slowing everything down (a chain of pipes has some overhead) or creating a memory leak (if one of those cloned Vinyl object is not collected properly). I think the best way to handle this is to delay creating the new streams up to the moment it's needed, rather than inside |
@mcollina nothing is related to gzip. This problem occurs when |
@mcollina I'm also very interest in the pattern of delaying the creation until it is needed. Do you have some examples of that pattern? |
@phated the first example in #202 (comment) without gzip in @phated more a general idea, and possibly a major bump in vinyl. Basically what you need is for the original entry to keep a reference on all the clones, and vice versa. Then you start flowing when all the clones have been piped (possibly in the |
@mcollina with no changes to vinyl or vinyl-fs, all of my tests & samples seem to work on node v4 and v5. So I think Streams3 outright fixed this problem. I'll open a new issue on the vinyl repo about a potential memory leak and cc you. Thanks again for all the help. |
I would recommend against using that, as it leaks memory. http://npm.im/cloneable-readable is what I recommend. |
I second this. readable-stream-clone has a bad memory leak.
|
I'm sorry if this is a support question but I've dug through everything I could find + reached out to people on twitter.
We've had an issue reported on the vinyl repo for quite some time that I am unable to solve: gulpjs/vinyl#55
The basics of the issue is that we are currently "cloning" a stream by T-ing it to another through stream but that seems to put it into paused mode.
Is there a proper way to clone a stream pipeline (and keep all the streams in the pipeline)?
The text was updated successfully, but these errors were encountered: