Skip to content
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

fix(runtime): "Error: EOF: end of file, read" on Windows #2238

Merged
merged 11 commits into from
Nov 10, 2020

Conversation

RomainMuller
Copy link
Contributor

@RomainMuller RomainMuller commented Nov 9, 2020

NodeJS makes it unsafe to perform syncrhonous (aka blocking) operations
on file descriptors 0 through 2 (STDIN, STDOUT, STDERR), as those are
set to O_NONBLOCK by libuv. This is particularly problematic on
Windows where there is no easy way to re-open those in blocking mode.

Consequently, we must handle some quirks in cases where blocking
attempts result in conditions typical of non-blocking access: EAGAIN
errors must be caught and retried, and EOF errors must be "ignored".

This PR adds the necessary code to correctly handle the EOF error, and
adds a 50ms sleep before re-trying a EAGAIN error that is achieved
thanks to a neat trick suggested by the sleep npm package:
using Atomics.wait enables syncrhonous sleep to be done in node
without having to ship a native module.


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@RomainMuller RomainMuller added effort/small Small work item – less than a day of effort os/windows Related specifically to Windows behavior labels Nov 9, 2020
@RomainMuller RomainMuller requested a review from a team November 9, 2020 09:56
@RomainMuller RomainMuller self-assigned this Nov 9, 2020
@mergify mergify bot added the contribution/core This is a PR that came from AWS. label Nov 9, 2020
@RomainMuller RomainMuller marked this pull request as draft November 9, 2020 13:53
NodeJS makes it unsafe to perform syncrhonous (aka blocking) operations
on file descriptors 0 through 2 (STDIN, STDOUT, STDERR), as those are
set to `O_NONBLOCK` by `libuv`. This is particularly problematic on
Windows where there is no easy way to re-open those in blocking mode as
can be done on most UNIX platforms today using `/dev/std{in,out,err}`
pseudo-files.

Consequently, we must handle some quirks in cases where blocking
attempts result in conditions typical of non-blocking access: `EAGAIN`
errors must be caught and retried, and `EOF` errors must be "ignored".

This PR adds the necessary code to correctly handle the `EOF` error, and
adds a 50ms sleep before re-trying a `EAGAIN` error that is achieved
thanks to a neat trick suggested by the [`sleep` npm package][sleep]:
using `Atomics.wait` enables syncrhonous sleep to be done in `node`
without having to ship a native module.

Additionally, this PRs re-opens `STDIN`, `STDOUT` and `STDERR` when the
`/dev/std{in,out,err}` files are present, reducing the incidence of this
problem on most UNIX platfoms.

[sleep]: https://www.npmjs.com/package/sleep
@RomainMuller RomainMuller changed the title chore(ci): test more combinations with Windows fix(runtime): "Error: EOF: end of file, read" on Windows Nov 9, 2020
@RomainMuller RomainMuller marked this pull request as ready for review November 9, 2020 14:59
@@ -1,3 +1,5 @@
import * as process from 'process';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added as part of my rumblings here... process.env is used here, and I kinda like to standardize on importing this even though it's implicit.

@@ -217,6 +217,7 @@ jobs:
python: '3.6'
# Test alternate .NETs
- java: '8'
# Current release info can be found at https://dotnet.microsoft.com/download/dotnet/5.0
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not strictly related to this PR, but this can be helpful in the future. This is kinda trivial, too. This got added as I was trying to find a way to reliably cause an EOF to happen on Windows in CI/CD. Spoiler: I did not succeed, for some reason.

Comment on lines +89 to +90
// eslint-disable-next-line no-constant-condition
while (true) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used a while loop instead of recursively re-entering, as this avoids stacking up in case EAGAIN happens a lot, which I imagine might be somewhat frequent on resource-constrained systems (where we'd likely also have less memory available for wasting on stack frames).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a nice comment to have in source, rather than just on the PR.

Copy link
Contributor

@njlynch njlynch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of my comments are about comments. :)

Also, are there any tests for this section of the code?

// force a O_SYNC access to STDIN in a reliable way within node.
// In order to make this stop we need to either stop depending on synchronous reads, or to
// provision our own communication channel that can reliably be synchronous. This work is
// "tracked" at https://github.com/aws/aws-cdk/issues/5187
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this was copy/pasted; is it still relevant? The referenced issue is closed. Do we have an active/open issue, and/or jsii issue to "track" this?


const EMPTY_BUFFER = Buffer.alloc(0);
const STDIN_FD = (process.stdin as any).fd ?? 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When will these (not) be set? Might deserve a comment.

const array = new Int32Array(new SharedArrayBuffer(4));

/**
* Sleeps for a set amount of time, syncrhonously.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Sleeps for a set amount of time, syncrhonously.
* Sleeps for a set amount of time, synchronously.

Comment on lines +89 to +90
// eslint-disable-next-line no-constant-condition
while (true) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a nice comment to have in source, rather than just on the PR.

@mergify
Copy link
Contributor

mergify bot commented Nov 10, 2020

Thank you for contributing! ❤️ I will now look into making sure the PR is up-to-date, then proceed to try and merge it!

@mergify mergify bot added the pr/ready-to-merge This PR is ready to be merged. label Nov 10, 2020
@mergify
Copy link
Contributor

mergify bot commented Nov 10, 2020

Merging (with squash)...

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildProject6AEA49D1-5lHf64IXfvmr
  • Commit ID: 10f8498
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@mergify
Copy link
Contributor

mergify bot commented Nov 10, 2020

Merging (with squash)...

@RomainMuller RomainMuller merged commit 1453ed3 into main Nov 10, 2020
@RomainMuller RomainMuller deleted the rmuller/windows-eof branch November 10, 2020 14:47
@mergify mergify bot removed the pr/ready-to-merge This PR is ready to be merged. label Nov 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution/core This is a PR that came from AWS. effort/small Small work item – less than a day of effort os/windows Related specifically to Windows behavior
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants