Silencing a Forked Process
How to provide the concurrency of a forked process without spamming the parent process‘ stdout.
I'm adding a feature to specjour which starts a manager in a subprocess when Bonjour fails to find any listening managers. This will enable the dream of specjour running the full suite with just one command instead of two. The first problem I ran into while working on this feature was that all of the debugging information that a manager prints, like the current test it's running, was being printed in-between the progress dots. The forked process was sharing the parent process' stdout. While this makes sense, it's undesirable.
A forked process sharing stdout
1 2 3 4 5 6 7 8 9 10 11 12 | |
A forked manager is essentially the same as running a manager in a terminal that gets minimized or backgrounded. All the user cares about are those little green dots so when a manager is forked, all of its output must be suppressed.
My first attempt was to use IO.pipe to hand off a nice clean IO object to the forked process. This worked some of the time but larger test suites would just hang. I finally learned that that a pipe's buffer is not infinite and over time, if you don't read it, your write will just sit there blocking, waiting to be read before continuing with to write.
Overloading the buffer of a pipe
1 2 3 4 5 6 7 8 | |
IO.pipe was the right idea but a little off. The underlying principle was to point $stdout to another IO object. Unfortunately, our pipe was space constrained. What we really need is a super sized, dumb IO object.
Thanks to
Shay Arnett
for reminding me of StringIO! Let's try it out.
Replacing stdout with a StringIO
1 2 3 4 5 6 7 | |
Excellent, it didn't hang! Now we have a silent forked process. Let's wrap it up:
QuietFork
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
Check out specjour to see how I actually use this thing.