Make Net:SSH update returned data packets/chunks in exec block more often

137 Views Asked by At

I have a ruby script on a remote server that I'm running via Net:SSH on my local pc.

The remote script takes a few minutes to run and outputs it's progress to stdout.

The problem I have is the block in my exec command only gets called when the packet/chunk is full.
So I get the progress all in one hit about each minute.

Here is some cut down examples that illustrate my problem:

Server Script:

(0.999).each do |i|
  puts i
  sleep 1
end
puts 1000

Local Script:

Net::SSH.start('ip.v.4.addr', 'user', :keys => ['my_key']) do |ssh|

  ssh.exec("ruby count_to_1000.rb") do |ch, stream, data|
    puts data if stream == :stdout
  end

  ssh.loop(1)

end

Is there any way from the remote script to force the sending of the packet/chunk?
Or is there a way to set a limit of say a second (or n bits) before it's flushed? (within Net:SSH)

Thanks for all your help!

2

There are 2 best solutions below

1
On BEST ANSWER

Try flush:

http://www.ruby-doc.org/core-2.1.5/IO.html#method-i-flush

(0.999).each do |i|
  puts i
  STDOUT.flush
  sleep 1
end

Or sync:

http://www.ruby-doc.org/core-2.1.5/IO.html#method-i-sync

STDOUT.sync = true
(0.999).each do |i|
  puts i
  sleep 1
end

(Untested, btw. Maybe they need to be used on the client-side instead, or on some other IO stream. But those are the two methods that immediately come to mind.)

1
On

In my test setup this works as expected (tested with localhost). However, there might be some issues with the STDOUT flush.

You can try to to write to STDOUT in stead of using puts (I have heard that there is some difference that I don't really understand).

Thus, you can on your server use:

(0.999).each do |i|
  STDOUT.puts i
  sleep 1
end
STDOUT.puts 1000
#You could possibly also use "STDOUT.write 1000", but it will not append a newline, like puts does.

If that does not work, then you can try to force-flush the STDOUT by using STDOUT.flush(). I believe the same can be achieved by writing an empty string to STDOUT, but I am not 1000% sure.

It might also happen that the exec command actually waits for the entire process to terminate for some reason(I was not able to figure out from the docs). In which case, you won't be able to achieve what you want. Then you can consider setting up websockets, use DRB, or some other means to pass the data.