question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Upload stream fires "data" after "end"

See original GitHub issue

Hi 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 via const stream = file.createReadStream();, it works just fine.
  • Using stream.pause() before setTimeout and then stream.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 use process.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:closed
  • Created 5 years ago
  • Comments:10 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
jaydensericcommented, Jan 15, 2019

The fix is published in v8.0.4!

1reaction
jaydensericcommented, Jan 14, 2019

I’m pretty sure the right event to listen for when handling file upload streams in resolvers is finish, not end:

https://github.com/jaydenseric/apollo-upload-examples/blob/d2bf708591ad276929976d3e4e26ae8005bf4b87/api/resolvers.mjs#L31

Read more comments on GitHub >

github_iconTop Results From Across the Web

busboy-connect fires on finish before the end of save file ...
This is expected behavior. finish is emitted when the last of the data has been read from the request (this includes any/all emitted...
Read more >
Getting Started with Node Streams - CODE Magazine
As the Readable stream pulls the data in from the file, it calls the function attached to the data event each time it...
Read more >
How to use node.js streams for fileupload - DEV Community ‍ ‍
Streams are a very basic method of data transmission. ... One of these events is 'open', which fires right after the stream is...
Read more >
Node.js Upload Files - W3Schools
When the file is uploaded and parsed, it gets placed on a temporary folder on your computer. Example. The file will be uploaded,...
Read more >
Filing Information Returns Electronically (FIRE) - IRS
Use the IRS Filing Information Returns Electronically (FIRE) system to file ... The following forms may be filed electronically via the FIRE System....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found