James White
James White

Reputation: 307

Node.js child process spawn issues with buffering?

For a project of mine I essentially want to be able to pass a command to a Node.js script and have it execute it and record the output line by line. This is what I have right now:

var child_process = require('child_process');
var child_spawn = child_process.spawn('ruby', ['test.rb']);

child_spawn.stdout.on('data', function(data) {

    console.log('stdout: ' + data);

});

Now when I tail -f the system log this works as I would except but when I test it with a trivial ruby script I wrote it recieves all the output at once as if it were buffered?

The script in question is:

puts "hello"
sleep(1)
puts "there"
sleep(1)
puts "my"
sleep(1)
puts "name"
sleep(1)
puts "is"
sleep(1)
puts "james"

When I run this on it's own it works as I'm sure you can imagine, printing out one line at a time with a second gap in between.

On the node docs (http://nodejs.org/api/child_process.html) I saw this:

(Note that some programs use line-buffered I/O internally. That doesn't affect node.js but it means data you send to the child process is not immediately consumed.)

Is that what is happening here and is there a way around it?

Upvotes: 1

Views: 1651

Answers (2)

James White
James White

Reputation: 307

vkurchatkin's (https://stackoverflow.com/a/20978696/483271) answer correctly explains the reason for why this happening.

How I actually got around this however was by making use of this https://github.com/chjj/pty.js/ (available on npm), it allows emulation of a terminal so Ruby doesn't buffer it's output and seems to have a compatible API to child_process from what I've seen so far.

Upvotes: 0

vkurchatkin
vkurchatkin

Reputation: 13570

That's exactly what happens. Check this:

puts "hello"
STDOUT.flush
sleep(1)
puts "there"
STDOUT.flush
sleep(1)
puts "my"
STDOUT.flush
sleep(1)
puts "name"
STDOUT.flush
sleep(1)
puts "is"
STDOUT.flush
sleep(1)
puts "james"
STDOUT.flush

I assume that ruby detects if stout is not a tty, and if so buffers all the output and flushes when the script exits. Putting STDOUT.sync = true seems to fix this issue.

Upvotes: 1

Related Questions