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

Deno.run with piped stdout gets stuck in specific scenarios #4568

Closed
lucacasonato opened this issue Apr 1, 2020 · 18 comments
Closed

Deno.run with piped stdout gets stuck in specific scenarios #4568

lucacasonato opened this issue Apr 1, 2020 · 18 comments
Assignees
Labels
bug Something isn't working correctly cli related to cli/ dir

Comments

@lucacasonato
Copy link
Member

lucacasonato commented Apr 1, 2020

Reproduction

  1. Generate test file:
echo "hello world" > file.txt
for i in {1..10}; do cat file.txt file.txt > file2.txt && mv file2.txt file.txt; done
  1. create test.js
const proc = Deno.run({
  cmd: ["cat", "test.json"],
  stdout: "piped",
  stderr: "piped"
});

const status = await proc.status();
  1. run test.ts
deno --allow-run test.js
  1. Deno gets stuck on await proc.status().
@ry
Copy link
Member

ry commented Apr 1, 2020

I can't repeat it.

@lucacasonato
Copy link
Member Author

Managed to narrow it down to only happening when the file that is being opened is stored on an NTFS drive - this is really weird. It's not happening on macOS for me either, just on Linux + file.txt on NTFS drive. If the file.txt is on ext4 its fine. I'll try on Windows and report back. This might be a weird NTFS driver bug on Linux though - had some of those before.

@lucacasonato
Copy link
Member Author

Checked on windows - not happening there. I'll close this and reopen if I have any more exact information about what is going on.

@lucacasonato
Copy link
Member Author

Ok I have a reliable reproduction, on macOS now:

  1. Save this file as lib.deno.d.ts: https://gist.github.com/lucacasonato/9a81ef88fa7f43ba8fc1297a04187ac9

  2. Create test.js:

const proc = Deno.run({
  cmd: ["deno", "doc", "lib.deno.d.ts", "--json", "--reload"],
  stdout: "piped",
  stderr: "piped"
});

const status = await proc.status();
  1. Run deno --allow-run test.js

  2. Deno gets stuck on await proc.status().

@lucacasonato lucacasonato reopened this Apr 2, 2020
@lucacasonato lucacasonato changed the title Deno.run with large amounts of newlines in piped stdout gets stuck Deno.run in piped stdout gets stuck in specific scenarios Apr 2, 2020
@lucacasonato lucacasonato changed the title Deno.run in piped stdout gets stuck in specific scenarios Deno.run with piped stdout gets stuck in specific scenarios Apr 2, 2020
@bartlomieju
Copy link
Member

@lucacasonato does error happen if you await proc.output() and await proc.stderrOutput() before awaiting on status? It seems that unit_test_runner produces similar sized output and works without a problem.

@lucacasonato
Copy link
Member Author

Everything works as expected when I add await proc.output() between the run call and the proc.status()call. await proc.stderrOutput() has no effect.

@ry ry added the bug Something isn't working correctly label Apr 2, 2020
@ry ry self-assigned this Apr 2, 2020
@youurayy
Copy link

This happens when the stdout is bigger than (?) 64KiB, consider:

const p = Deno.run({

  // this will work in any case:
  // cmd: [ 'curl', '-s', 'https://deno.land' ], // 4KB

  // this will work only if stdout is drained below:
  cmd: [ 'curl', '-s', 'https://en.wikipedia.org/wiki/Deno_(software)' ], // 79KB

  stdout: 'piped',
  stderr: 'piped'
})

console.log('here 1')

// await p.output() // drain the stdout here
console.log('here 1.1')

await p.stderrOutput()
console.log('here 1.2')

const { code } = await p.status()
console.log('here 2, code: ' + code)

You have to uncomment the // drain the stdout here line to make the Wikipedia link work.
Tested on Windows.
Run with deno run --allow-run test.js.

@bartlomieju bartlomieju added the cli related to cli/ dir label May 21, 2020
lucacasonato added a commit to lucacasonato/deno_lint that referenced this issue Jun 2, 2020
lucacasonato added a commit to lucacasonato/deno_lint that referenced this issue Jun 2, 2020
@lucacasonato
Copy link
Member Author

I just ran into this again on the registry. It is a very annoying bug because it is so not logical. I think many people have and will run into it. I also ran into it for doc.deno.land. We should really address this one soon.

@exside
Copy link
Contributor

exside commented Sep 10, 2020

@lucacasonato I think I did run into some form of it: #7208 (comment) but can't explain it...

@ebebbington
Copy link
Contributor

ebebbington commented Oct 11, 2020

@lucacasonato I get the same issue when the sub process is asking for stdin (similar to what i mentioned before), it just hangs on the await p.status(), not sure in this scenario if it's possible to address or even a bug

@roman-kirsanov
Copy link

encountered same issue again! here is my work around:

const proc = Deno.run({ cmd, stderr: 'piped', stdout: 'piped' });
const [ stderr, stdout, status ] = await Promise.all([ proc.stderrOutput(), proc.output(), proc.status() ]);

@Soremwar
Copy link
Contributor

Soremwar commented Dec 16, 2020

Still happening on latest canary

@ry ry assigned bartlomieju and unassigned ry Feb 2, 2021
@bartlomieju
Copy link
Member

bartlomieju commented Feb 3, 2021

So after further investigation I think this works as it should.

stdout and stderr pipes should be closed manually before awaiting on the status, so @rok-star's solution is the preferable one for the time being. I will update the docs for the Deno.run API accordingly (edit: #9390), but overall the API is not very user-friendly and I think it might have to undergo a rework for 2.0 to make it more like Tokio's Child API (I will open a separate issue for it).

@lucacasonato I get the same issue when the sub process is asking for stdin (similar to what i mentioned before), it just hangs on the await p.status(), not sure in this scenario if it's possible to address or even a bug

@ebebbington this should no longer be the case, calling p.status() will close stdin of the child process before awaiting on the status to avoid the deadlock (https://docs.rs/tokio/1.1.1/tokio/process/struct.Child.html#method.wait).

@ebebbington
Copy link
Contributor

@bartlomieju ok cool thanks, I’ll just mention that this issue doesn’t affect me anymore I guess as I moved to another solution but good to hear it is addressed

@dgreensp
Copy link

dgreensp commented Jun 6, 2022

This was very surprising to encounter, and I don't know what I would have done if I hadn't found this issue!

FWIW the examples of Deno.run that I was working off of (incorrectly) read status before output, e.g. in the manual: https://deno.land/manual/examples/subprocess . I wouldn't have thought to specifically read the docs for the Process type.

@aapoalas
Copy link
Collaborator

Is this still happening, or has the deadlock been fixed?

@tiesselune
Copy link

This is still happening (just ran into it using Deno.run, but the documentation does warn the user that stdout and stderr must be closed when piped so the process can exit. (So output must be read, basically, before calling status)

The surprising part is that it does not happen on "small" outputs, only on big ones, which is a bit destabilizing (and can result in seemingly arbitrary hangs when other commands succeed), reason for which I stumbled on this thread in the first place...

@crowlKats
Copy link
Member

This doesn't happen with the new subprocess API (Deno.Command), so closing since Deno.run is deprecated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working correctly cli related to cli/ dir
Projects
None yet
Development

No branches or pull requests