Upload stream fires "data" after "end"
See original GitHub issueHi again,
Node v10.14.1, graphql-upload v8.0.3.
An odd one here, possibly not a bug, might also be a mistake on my side. Either way, would appreciate your advice! : ]
First, simplified example code. I use this code to upload a file to my GraphQL server. The type of input.icon
is Upload.
The call to setTimeout
simulates certain asynchronous logic present in my code. I perform an asynchronous call somewhere in the program, wait for a response, and only then I pipe the upload stream to where I want it to go.
const create = input =>
new Promise(resolve => {
input.icon.then(file => {
const stream = file.createReadStream();
setTimeout(() => {
stream.on("data", () => {
console.log("Receiving data");
});
stream.on("end", () => {
console.log("Stream ended");
resolve();
});
}, 300);
});
});
This code works fine and prints Receiving data a number of times and finishes with Stream ended. However, there is a condition when this does not work:
- The uploaded file is really small - smaller than the
readableHighWaterMark
. - The
"end"
event handler is literally attached before the data handler, like this:
setTimeout(() => {
stream.on("end", () => {
console.log("Stream ended");
resolve();
});
stream.on("data", () => {
console.log("Receiving data");
});
}, 300);
In this case, the code will print Stream ended first, and then Receiving data.
Some more notes:
- The code works fine if I use a different type of stream, not the one from graphql-upload. E.g. if I write
const stream = fs.createReadStream("/home/juona/ex.tar.bz2");
to read the same file from the local file system, instead of uploading it viaconst stream = file.createReadStream();
, it works just fine. - Using
stream.pause()
beforesetTimeout
and thenstream.resume()
anywhere in the timeout callback fixes the problem. - The code also works correctly if
setTimeout
is removed or if the timeout is very low (e.g. if I useprocess.nextTick()
instead), regardless of the order of event handler attachment. I would assume that the timeout has to be longer than the time it takes to upload the file. - It does not matter what kind of file is being used, only its size.
I am having trouble understanding what is happening here. In the actual application I use a bunch of other stream libraries to transform the upload and one of them fails because it expects stream.end
to be called after at at least one stream.write
, which I guess is a fair expectation. Also the problem is more complex in the real scenario since stream.pause()
does not really help in that case, but I have to start the investigation somewhere…
Could perhaps be an issue in Node itself or a compatibility problem, but since it matters whether or not I use the upload stream or a different one, I am coming to you first.
Any thoughts?
Issue Analytics
- State:
- Created 5 years ago
- Comments:10 (4 by maintainers)
The fix is published in v8.0.4!
I’m pretty sure the right event to listen for when handling file upload streams in resolvers is
finish
, notend
:https://github.com/jaydenseric/apollo-upload-examples/blob/d2bf708591ad276929976d3e4e26ae8005bf4b87/api/resolvers.mjs#L31