Skip to content

use 'close' event on file stream for reliability - #787

Closed
Trott wants to merge 1 commit into
expressjs:masterfrom
Trott:de-flake-test
Closed

Trott wants to merge 1 commit into
expressjs:masterfrom
Trott:de-flake-test

Conversation

@Trott

@Trott Trott commented Oct 11, 2019

Copy link
Copy Markdown
Contributor

Change listened-for event on the output stream in storage/disk.js from
'finish' to 'close' to improve reliability. With 'finish', there is a
race condition such that sometimes the callback runs before the file
exists.

Refs: #238

Change listened-for event on the output stream in storage/disk.js from
'finish' to 'close' to improve reliability. With 'finish', there is a
race condition such that sometimes the callback runs before the file
exists.

Refs: expressjs#238
@Trott

Trott commented Oct 11, 2019

Copy link
Copy Markdown
Contributor Author

/ping @mcollina @ronag Does this seem like the correct event to listen for in this situation, or was the previous code correct and this is indicative of a more elusive problem?

@Trott Trott mentioned this pull request Oct 11, 2019
@ronag

ronag commented Oct 11, 2019 •

Copy link
Copy Markdown

That's interesting. 'finish' should be fine. I will dig into this. What version of node?

In the meantime this workaround is not entirely correct either, you might end up invoking the callback twice since 'close' will/should be emitted after 'error'. Also you are not handling the 'error' event from the source stream.

      cb = once(cb)
      var finalPath = path.join(destination, filename)
      var outStream = fs.createWriteStream(finalPath)

      file.stream.pipe(outStream)
      file.stream.on('error', err => {
        outStream.destroy()
        cb(err)
      })
      outStream.on('error', cb)
      outStream.on('close', function () {
        cb(null, {
          destination: destination,
          filename: filename,
          path: finalPath,
          size: outStream.bytesWritten
        })
      })

Also are you aware that _handleFile will not destroy/free the source stream upon failure? I'm not sure if that might cause file descriptor leaks elsewhere.

Furthermore this code assumes that the source stream has not already completed. If it has completed this will never call the callback. But I guess that's a minor.

@ronag

ronag commented Oct 11, 2019 •

Copy link
Copy Markdown

Yes, I think this might be a bug in node. Streams can emit 'finish' before 'open' if no data has been written before end(), thus causing a race condition.

@ronag

ronag commented Oct 11, 2019

Copy link
Copy Markdown

nodejs/node#29930

@Trott

Trott commented Oct 11, 2019

Copy link
Copy Markdown
Contributor Author

That's interesting. 'finish' should be fine. I will dig into this. What version of node?

@ronag I was using Node.js 12.11.1.

@Trott

Trott commented Oct 11, 2019

Copy link
Copy Markdown
Contributor Author

nodejs/node#29930

Awesome and thank you! I'll close this.

@Trott Trott closed this Oct 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants