-
Notifications
You must be signed in to change notification settings - Fork 88
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
'run' hangs on large output #52
Comments
This is a very interesting bug.
let l = runAsync(bash: "for i in {1..65537}; do echo -n =; done")
try l.finish()
print(l.stdout)
I think this bug is the same as #15. We can't use the same fix used then because "run" has been redesigned since then and has to finish before reading its output. I want it to be possible to use "run" without reading any output at all. Here is a workaround: _ = runAsync(bash: "for i in {1..65537}; do echo -n =; done").stdout.read() This will make sure the output of the command has been closed (and therefore the command has finished running) before continuing. |
The problem is described here: https://stackoverflow.com/a/39281558/96587 It happens when the output pipe from the command is full. So the problem is with Foundation's Process and FileHandle classes. Not really much we can do about it in SwiftShell except for informing users about it. I'll add it to the README. |
Would it be possible to read the output, but not necessarily return it unless requested? Perhaps it'd incur a small performance hit, but this issue makes |
You’re right, this is pretty dangerous. There doesn’t seem to be any way of increasing the buffer size either. To reduce overhead we could store the output as just Data, and convert to String only upon request. One problem though: we might have to read from stdout and stderror simultaneously. Because if we try to read all output from stdout in one go and the command fills up stderror (or the other way around), the command will still hang. I won’t be able to implement this for a couple of weeks, any pull requests are welcome if you want to do it. |
@ileitch Actually i don’t think stderror should ever contain more than 65KB (I mean how much error information can a command produce?). Do you think it would suffice to just read all Data from stdout before waiting for command to finish? |
I don't think it's safe to make assumptions about what amount of stderr output might be produced. I'm of the opinion that this method should not hang under any circumstance. |
I think I too have been running into this issue when using Swift Shell to run some Handbrake transcoding commands (there's a whole lot of output even without it running verbosely). I am ending up with several zombied Handbrake processes and my program is left hanging. I have verified that it is not issuing a log command immediately after my SwiftShell.run() and so I suspect I too am hitting this problem. Because of how I am using the result of the SwiftShell.run(), it would not be easy for me to use the runAsync workaround. I am testing the fix in #54 right now to see if it resolves my issue. |
I was previously using my own homemade class for running shell commands which worked, but I wanted a bit more power/functionality and didn't want to build it myself. That's when I found this framework and just recently started using it instead. It has the same clean usage as my homemade solution, but it far more powerful/organized and meant I've got one less thing to manage myself. As soon as I switched to this though, I started noticing my handbrake commands were frequently hanging or becoming zombies and my program would hang. Due to my busy schedule I hadn't had time to look into it until today, which is when I saw this issue and thought it may be related to my problem. |
@ileitch @Ponyboy47 Have you had a chance to test out pull request 54? Did it work? |
Sorry I forgot to respond after testing this. Yes the fix in #54 did allow my program to continue execution as expected :) |
Sorry I haven't tried it. I stopped using SwiftShell when I discovered this issue. The PR looks good though 👍🏼 |
Excellent, I have merged the PR and will release a new version as soon as the CI tests pass. |
Could you post the code, including the shell command? |
let asyncCommand = SimulatorCommand.executeBuild(xctestrunFilePath, onSimulatorWithId: self.simulator.id) { value in
print("The command has truly ended")
}
asyncCommand.stop()
_ = try? asyncCommand.finish()
_ = asyncCommand.exitcode()
asyncCommand.stdout.read()
asyncCommand.stderror.read() This is the code i ran. |
The first line runs your [Edit] - let me check again. I use the |
OK it looks like this had something to do with it. |
Using version 4.0.0 this commad hangs:
run(bash: "for i in {1..100000}; do echo -n =; done")
The text was updated successfully, but these errors were encountered: