[Backgroundrb-devel] "tailing" a running system command?

mattp at digimonkey.com mattp at digimonkey.com
Wed Aug 16 17:47:23 EDT 2006


Check it out... I got it working:

[ worker ]
class PingWorker < BackgrounDRb::Rails
   attr_accessor :result

   def do_work(args)
     @result = IO.popen("ping -n 10 www.google.com")
   end
end

[ controller ]
def ping_task
   session[:job_key] = MiddleMan.new_worker(:class => :ping_worker)
end

def ping_response
   if request.xhr?
     msg = MiddleMan.get_worker(session[:job_key]).result.gets
     render :update do |page|
       if msg.nil?
         MiddleMan.delete_worker(session[:job_key])
         # ??? need some way to stop the PeriodicalExecuter.
       else
         page.insert_html :bottom, 'ping_result', msg+'<br />'
       end
     end
   else
     redirect_to :action => 'index'
   end
end

[ view ]
<div id="ping_result"></div>
<%= periodically_call_remote(:url => {:action => :ping_response},  
:frequency => 1) -%>


Now if I can just figure out a way to stop the PeriodicalExecuter...

[mp]

Quoting Charles Brian Quinn <me at seebq.com>:

> We're working on a super cool new tool to help automate capistrano and
> rake deployment task running on remote servers, and we do something
> similiar to this using backgrounDRb (thanks Ezra!).
>
> It is based off our RailsDay 2006 entry:
> http://heartbeat.highgroove.com/ -- enough with the bragging, here is
> how we do it:
>
> your worker now needs to have an @output class variable (instead of   
> progress).
>
> in your worker, you can run the task one of two ways which might or
> might not work:
>
>        # you can use Kernel.system to make the call which I don't
> know how you get output
>        if not Kernel.system("ping google)
>          errors.add_to_base(" your error here ") # this is
> technically in a model hence the errors obj
>          raise
>        end
>
>        # or:
>        cmd_to_run = "ping google"
>
>        stdin, stdout, stderr = Open3.popen3(cmd_to_run)
>
>        s_stderr = stderr.read.to_s
>        s_stdout = stdout.read.to_s
>
>        # if you'd like to see it
>        logger.info "stdout: #{s_stdout}"
>        logger.info "stderr: #{s_stderr}"
>
>        if s_stderr.empty? && s_stdout.starts_with?("error stuff here")
>          return true
>        else
>          errors.add_to_base("error msg here")
>          return false
>        end
>
> But, as for setting your @output, well, you'd need to run inside a
> loop or perhaps even in another thread within the bg worker thread.
> We don't need to do this because we're executing our task using ssh
> and we have an open channel and just do @output << in the loop as it
> runs.  You may not be able to use the popen3 calls above, to be honest
> -- the read pretty much kills that idea. Our worker method that
> appends output looks like:
>
>    Net::SSH.start( host,
>                    :username => username,
>                    :password => password,
>                    :port => port ) do |session|
>      session.open_channel do |channel|
>
>        channel.on_data do |ch, data|
>          @output << "#{data}"
>        end
>
>        channel.on_extended_data do |ch, type, data|
>          @output << "#{data}"
>        end
>
>        channel.exec( "ping google\n" )
>      end
>      session.loop
>    end
>
> Maybe you can find a simliar asynchronous call for executing methods,
> that updates output as it runs.
>
> Now, in your controller:
>
> the method, let's say execute:
>
> def execute
>  session[:job_key] = Middleman....  # call your worker
> end
>
> and for the view we used rjs to update a page (a lightbox actually):
>
>  <div id="task_output">
>    Connecting to Server...
>  </div>
>
> execute.rjs:
>
> page << "showBG();"
> page << "showIbox('#{url_for(:action => 'output', :id =>
> @task)}','',parseQuery('width=760&height=400'))"
> page << "output = new
> Ajax.PeriodicalUpdater('task_output','#{url_for(:action =>
> 'update_output', :id=> @task.id)}',2);"
>
> back to your controller, it can be as simple as:
>
>  def update_output
>    @job = MiddleMan.get_worker(session[:job_key])
>    render :inline => '<%= simple_format(@job.output) %>'
>  end
>
> The hard part will be appending @output as it's running.  I know I
> didn't answer the @output side, but hopefully helped with the
> backgroundrb worker side.
>
> cheers and good luck, let us know how it goes.
>
> On 8/16/06, mattp at digimonkey.com <mattp at digimonkey.com> wrote:
>> Dunno if anyone saw the short question at the end of my last thread,
>> so i'm reposting in a thread with the appropriate subject:
>>
>> Here's what I need to do --
>>
>> Run a system-level command like 'ping -t www.google.com' and have it
>> periodically update a <div> with the command's ouput.  Is this possible?
>>
>> (the trick here is that I want *periodic* updates of the div... i want
>> to see incremental output as 'ping' is running, just like if I were
>> looking at console...)
>> _______________________________________________
>> Backgroundrb-devel mailing list
>> Backgroundrb-devel at rubyforge.org
>> http://rubyforge.org/mailman/listinfo/backgroundrb-devel
>>
>
>
> -- 
> Charles Brian Quinn
> self-promotion: www.seebq.com
> highgroove studios: www.highgroove.com
> slingshot hosting: www.slingshothosting.com




More information about the Backgroundrb-devel mailing list