-
Notifications
You must be signed in to change notification settings - Fork 230
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
Proposal: add _flush to Writable streams #112
Comments
This is something I've needed and had to implement my own half baked On Thu, Feb 12, 2015, 11:57 AM Mark Stosberg notifications@github.com
|
+1, got one of these in WHATWG streams already (under the name "close", although now I am contemplating whether flush is nicer). |
The tricky thing is that transform flush is after writable half has On Thu, Feb 12, 2015, 12:52 PM Domenic Denicola notifications@github.com
|
@calvinmetcalf I'm a little confused by:
My impression is that we would preserve and extend this behavior to Writables as well. Am I misunderstanding? I am also curious: what is the order of events?
OR:
|
there is no point in flushing writable after finish. the whole idea is to defer finish |
@chrisdickinson like @vkurchatkin said we want to defer finish, adding in new function (like calling it close) that fires earlier would likely be the only backwards compatible way to do it, we could leave _flush in but depreciate it. |
@calvinmetcalf I was thinking about |
I am not that opinionated about this. Is there any reason why we couldn't move it from |
@vkurchatkin I was assuming closing resources would be a use case for this @sonewman because the transform one happens after finish is emitted and we'd want it to delay finish being emitted. |
Why not call it |
@mafintosh and then simply end when passing it to the simplified constructor |
@calvinmetcalf yea! and transforms would support both flush and end (different use cases). i know this would simplify a lot of my code. |
@calvinmetcalf function prefinish(stream, state) {
if (!state.prefinished) {
state.prefinished = true;
stream.emit('prefinish');
}
}
function finishMaybe(stream, state) {
var need = needFinish(stream, state);
if (need) {
if (state.pendingcb === 0) {
prefinish(stream, state);
state.finished = true;
stream.emit('finish');
} else
prefinish(stream, state);
}
return need;
} |
Also i don't think it would be right for Having a I do think we should start addressing these stream lifecycle things as part of a stream |
The thing is, there is always going to be more, and more(,...and more,...) new things people are going to want, to instrument their stream in some specific way. Open up a model for the underlying sources and those things are easy for anyone to instrument to any requirement. To be clear, I am not saying any of these ideas are bad, as they are generic and useful. But IMO going forward we need to open up this cycle/internals for people to customise at their will, meaning the base of streams can be simple and avoid continuous scope creep. @sonewman - gets off soap box |
sorry it's that finish can be called before _flush is done if it's async. I seem to remember testing what would happen if you did delay it and it causing quite a few node transform streams to break. |
@calvinmetcalf hmmm, interesting. I can see how that would be true, since |
the |
@sonewman @calvinmetcalf moving the flush function to writable streams is a major change since the flush function currently is called before the readable part of the stream ends (not the writable). |
so _flush is part of the public api and when it is called is documented. This was why I was suggesting a new function name. |
I think I am +1 on doing this, it seems like that would actually be useful. @mafintosh |
@sonewman my point is that the var transform = stream.Transform({
transform: function (data, enc, cb) {
cb(null, data)
},
flush: function(cb) {
setTimeout(function () {
transform.push('world')
cb()
}, 1000)
}
})
transform.on('data', function (data) {
console.log(data.toString())
})
transform.on('finish', function() {
console.log('(finish)')
})
transform.on('end', function() {
console.log('(end)')
})
transform.write('hello')
transform.end() running the above will result in
|
which is why i think having it being called something like var stream = require('stream')
var transform = stream.Transform({
transform: function (data, enc, cb) {
cb(null, data)
},
end: function (cb) {
setTimeout(function() {
transform.push('before finish')
cb()
}, 1000)
},
flush: function (cb) {
setTimeout(function () {
transform.push('world')
cb()
}, 1000)
}
})
transform.on('data', function (data) {
console.log(data.toString())
})
transform.on('finish', function() {
console.log('(finish)')
})
transform.on('end', function() {
console.log('(end)')
})
transform.write('hello')
transform.end() -->
|
@mafintosh whether something comes after But the point I am trying to make is that function finishWritable(stream, state) {
if (state.pendingcb === 0) {
state.finished = true;
stream.emit('finish');
}
}
function prefinish(stream, state) {
if (!state.prefinished) {
state.prefinished = true;
stream.emit('prefinish');
if ('function' === typeof stream._flush)
stream._flush(() => finishWritable(stream, state));
else
finishWritable(stream, state);
}
}
function finishMaybe(stream, state) {
var need = needFinish(stream, state);
if (need)
prefinish(stream, state);
return need;
} |
@vkurchatkin Ah, I see. Transform currently hooks onto @mafintosh I'm -1 on calling it "end". Between "end" events, "end" methods, and the "finish" events, the term is a bit overloaded as it stands. @sonewman I agree that the proposed |
Arg, yes, Alternatively, |
@chrisdickinson having simple constructor is there a use case for adding |
@mafintosh Re: delaying
If we use the simplified constructor API to introduce this behavior, we can sidestep that breakage, but still introduce the functionality for all Writables (duplexes and transforms included) It is a little weird that I just noticed this when rereading the thread, but one of the originally linked issues suggested this feature for the purposes of batch writes – specifically, so that a batching writer can be made aware of the end of the stream and output the rest of its data before close. However, we already have a mechanism for batching writes – Are there other valid uses for this feature outside of batch writes? |
I have a couple of use cases myself: In pumpify (turns multiple writable/readable streams into a single one) I don't want to emit In content-addressable-blob-store we write to a tmp file that we want to move somewhere before emitting |
@chrisdickinson @calvinmetcalf we could just break |
@chrisdickinson writev, cork, and uncork don't actually do the trick because they must be explicitly called by the caller so don't work cases like when the stream is being piped too. Besides batch writes there is also closing underlying resources hence why the name _close came up. While _end is a bit confusing due to the event it d ones fit with the pattern of write, writev, and read. @mafintosh I totally don't think it's worth a major version bump, I'd call it __flush before bumping the major. |
Hmm, i don't know. I can't see how |
Noting this here: it seems like there's interest in |
I will expand my thoughts: We have a problem with TLS streams in core at the moment. Current implementation calls
|
Yeah, and my use case needs callback. |
@indutny Curious: if there's a write going out during |
@chrisdickinson nope. In case of TLS, this write is happening internally in C++. |
Just in case, I'm going to stub out some implementation and share it with you guys. |
See nodejs/node#1164 |
So far I haven't reunified it with transform, so it is called |
Finished the PR there, PTAL. |
This is currently being proposed in nodejs/node#12828. |
merged into node as |
@TomFrost made a good case for this pre-fork:
nodejs/node-v0.x-archive#7631
There was also significant discussion previously in this issue:
nodejs/node-v0.x-archive#7348
@TomFrost also implemented a workaround that is published on npmjs.org:
https://www.npmjs.com/package/flushwritable
Perhaps it will be helpful in considering the issue.
I'm one of the other developers from the previous thread that would also find it to be useful.
The text was updated successfully, but these errors were encountered: