OK I know whats happening. Your while loop completes and calls kill on the worker before your task_progress controller method ever gets called> So the worker is deleted and when you try to access it from rails you get an error because there is no longer a worker at that job key. The kill method is meant to be used within a worker that you fire and forget. If you want to get the results then you should not call kill right in your worker. You can call kill or delete_worker from rails in your done method. So if you want to see the progress bar working I suggest you put a sleep in the while loop. A while loop with no sleep can count to 1200 before you could blink and then the kill method gets called and your screwed. So add sleep 0.3 or somethign within the while loop so you can see it work. And if you want to see the results of your worker in rails you should call the kill method from rails through the middlwman. If you want to just fire and forget a worker then you want to call kill within the worker when it is done working. Other then that your code is fine. Give it another shot with some sleep in the loop. Cheers- -Ezra On Aug 16, 2006, at 10:25 AM, mattp at digimonkey.com wrote:> Weird is, I had it working a second ago and then reloaded the > webrick server and now it''s erroring out with: > > NoMethodError (You have a nil object when you didn''t expect it! > The error occured while evaluating nil.progress): > /app/controllers/operations_controller.rb:14:in `task_progress'' > > Here''s the code -- > > [ /lib/workers/ping_worker.rb ] > > class PingWorker < BackgrounDRb::Rails > > attr_accessor :progress > > def do_work(args) > @progress = 0 > calculate_the_meaning_of_life(args) > kill > end > > def calculate_the_meaning_of_life(args) > while @progress < 100 > @progress += 1 > end > end > > end > > [ operations_controller.rb ] > > class OperationsController < ApplicationController > sidebar :general > sidebar :operations > > # start new worker and put the job_key into the session so you can > # get the status of your job later. > def background_task > session[:job_key] = MiddleMan.new_worker(:class => :ping_worker, > :args => {:baz => > ''hello!'', :qux => ''another arg!''}) > end > > def task_progress > if request.xhr? > progress_percent = MiddleMan.get_worker(session > [:job_key]).progress > render :update do |page| > page.call(''progressPercent'', ''progressbar'', progress_percent) > page.redirect_to( :action => ''done'') if progress_percent >= > 100 > end > else > redirect_to :action => ''index'' > end > end > > def results > @results = MiddleMan.get_worker(session[:job_key]).results > MiddleMan.delete_worker(session[:job_key]) > end > > def done > end > > end > > Quoting Ezra Zygmuntowicz <ezmobius at gmail.com>: > >> >> On Aug 16, 2006, at 10:08 AM, backgroundrb-devel- >> bounces at rubyforge.org wrote: >> >>> >>> From: mattp at digimonkey.com >>> Date: August 16, 2006 10:01:26 AM PDT >>> To: backgroundrb-devel at rubyforge.org >>> Subject: newbie needs help >>> >>> >>> I''m sure this is the billionth newbie help request on here, but >>> I sure am hitting my head against the wall on this. >>> >>> I''ve tried numberous of Ezra''s examples that I was able to find >>> online. The best I''m able to get is nothing happens and >>> development log says: >>> >>> NoMethodError (undefined method `progress'' for #<PingWorker: >>> 0x3a786c0>): >>> /app/controllers/operations_controller.rb:13:in `get_progress'' >>> >>> Any ideas? I''m sure there''s a basic thing I''m not doing >>> right... but I couldn''t figure out what that might be, based on >>> the documentation. >>> >>> [mp] >>> >>> >> >> >> Hi Matt- >> >> It looks like you are missing something. Can you post your worker >> class? It looks like you either need a progress method or you need to >> set attr_accessor :progress in your worker. >> >> >> -Ezra > >
mattp at digimonkey.com
2006-Aug-16 17:48 UTC
[Backgroundrb-devel] Forward of moderated message
That did it. Thanks! As a note that might be helpful to others -- If you are using windows and RadRails for development, you need to be sure and restart the backgroundrb server in your cmd.exe console window after you make changes to the *_worker.rb files. I''m sure Ezra can explain why (I can''t.) Ok, so for my next question: Now that my stupid progress counter is working, on to what I really want 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? [mp] Quoting Ezra Zygmuntowicz <ezmobius at gmail.com>:> OK I know whats happening. Your while loop completes and calls kill on > the worker before your task_progress controller method ever gets > called> So the worker is deleted and when you try to access it from > rails you get an error because there is no longer a worker at that job > key. The kill method is meant to be used within a worker that you fire > and forget. If you want to get the results then you should not call > kill right in your worker. You can call kill or delete_worker from > rails in your done method. > > So if you want to see the progress bar working I suggest you put a > sleep in the while loop. A while loop with no sleep can count to 1200 > before you could blink and then the kill method gets called and your > screwed. So add sleep 0.3 or somethign within the while loop so you can > see it work. > > And if you want to see the results of your worker in rails you should > call the kill method from rails through the middlwman. If you want to > just fire and forget a worker then you want to call kill within the > worker when it is done working. > > Other then that your code is fine. Give it another shot with some > sleep in the loop. > > Cheers- > -Ezra > > > > On Aug 16, 2006, at 10:25 AM, mattp at digimonkey.com wrote: > >> Weird is, I had it working a second ago and then reloaded the >> webrick server and now it''s erroring out with: >> >> NoMethodError (You have a nil object when you didn''t expect it! >> The error occured while evaluating nil.progress): >> /app/controllers/operations_controller.rb:14:in `task_progress'' >> >> Here''s the code -- >> >> [ /lib/workers/ping_worker.rb ] >> >> class PingWorker < BackgrounDRb::Rails >> >> attr_accessor :progress >> >> def do_work(args) >> @progress = 0 >> calculate_the_meaning_of_life(args) >> kill >> end >> >> def calculate_the_meaning_of_life(args) >> while @progress < 100 >> @progress += 1 >> end >> end >> >> end >> >> [ operations_controller.rb ] >> >> class OperationsController < ApplicationController >> sidebar :general >> sidebar :operations >> >> # start new worker and put the job_key into the session so you can >> # get the status of your job later. >> def background_task >> session[:job_key] = MiddleMan.new_worker(:class => :ping_worker, >> :args => {:baz => >> ''hello!'', :qux => ''another arg!''}) >> end >> >> def task_progress >> if request.xhr? >> progress_percent = MiddleMan.get_worker(session[:job_key]).progress >> render :update do |page| >> page.call(''progressPercent'', ''progressbar'', progress_percent) >> page.redirect_to( :action => ''done'') if progress_percent >= 100 >> end >> else >> redirect_to :action => ''index'' >> end >> end >> >> def results >> @results = MiddleMan.get_worker(session[:job_key]).results >> MiddleMan.delete_worker(session[:job_key]) >> end >> >> def done >> end >> >> end >> >> Quoting Ezra Zygmuntowicz <ezmobius at gmail.com>: >> >>> >>> On Aug 16, 2006, at 10:08 AM, backgroundrb-devel- >>> bounces at rubyforge.org wrote: >>> >>>> >>>> From: mattp at digimonkey.com >>>> Date: August 16, 2006 10:01:26 AM PDT >>>> To: backgroundrb-devel at rubyforge.org >>>> Subject: newbie needs help >>>> >>>> >>>> I''m sure this is the billionth newbie help request on here, but I >>>> sure am hitting my head against the wall on this. >>>> >>>> I''ve tried numberous of Ezra''s examples that I was able to find >>>> online. The best I''m able to get is nothing happens and >>>> development log says: >>>> >>>> NoMethodError (undefined method `progress'' for #<PingWorker: 0x3a786c0>): >>>> /app/controllers/operations_controller.rb:13:in `get_progress'' >>>> >>>> Any ideas? I''m sure there''s a basic thing I''m not doing right... >>>> but I couldn''t figure out what that might be, based on the >>>> documentation. >>>> >>>> [mp] >>>> >>>> >>> >>> >>> Hi Matt- >>> >>> It looks like you are missing something. Can you post your worker >>> class? It looks like you either need a progress method or you need to >>> set attr_accessor :progress in your worker. >>> >>> >>> -Ezra >> >>
mattp at digimonkey.com
2006-Aug-16 20:14 UTC
[Backgroundrb-devel] "tailing" a running system command?
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...)
Günter Ladwig
2006-Aug-16 20:31 UTC
[Backgroundrb-devel] "tailing" a running system command?
On 16.08.2006, at 22:14, mattp at digimonkey.com wrote:> 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...)Yes, it should be possible. Have a look at the Rails function periodically_call_remote. In the controller method you could then get the output from your worker and replace the HTML in a particular <div>-tag. G?nter
Charles Brian Quinn
2006-Aug-16 21:19 UTC
[Backgroundrb-devel] "tailing" a running system command?
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
mattp at digimonkey.com
2006-Aug-16 21:47 UTC
[Backgroundrb-devel] "tailing" a running system command?
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
Ezra Zygmuntowicz
2006-Aug-16 23:02 UTC
[Backgroundrb-devel] "tailing" a running system command?
Very cool! I finally figured out how to stop a periodically_call_remote via rjs or js. Do it like this, in the view where you render your periodic call: <script>stop_polling = false;</script> <%= periodically_call_remote(:url => {:action => ''update_results''}, :frequency => 5, :condition => "stop_polling == false") %> <a href=''#'' onclick="stop_polling=true">Stop Polling</a> #Or if you need to tell it to stop from the controller via rjs: def stop_polling render :update { |p| p.assign ''stop_polling'', true } end And thats it, the periodic call will stop polling once the js variable stop_polling is set to true. Of course you could also just set it to true in the view but it depends on where you get the info that tells you to stop polling. Cheers- -Ezra On Aug 16, 2006, at 2:47 PM, mattp at digimonkey.com wrote:> 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 > > > _______________________________________________ > Backgroundrb-devel mailing list > Backgroundrb-devel at rubyforge.org > http://rubyforge.org/mailman/listinfo/backgroundrb-devel >
mattp at digimonkey.com
2006-Aug-16 23:15 UTC
[Backgroundrb-devel] "tailing" a running system command?
Nice. Based on your suggestion, I also found a simpler way (for me at least). [controller] 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]) page.remove(''spinner'') page.call(''stop_xhr'') # <=== LOOK HERE! THIS IS THE FANCY BIT!! else page.insert_html :bottom, ''ping_result'', msg+''<br />'' end end else redirect_to :action => ''index'' end end [view] <script language="javascript"> var stop_polling = false; function stop_xhr() { stop_polling = true; } </script> <%= periodically_call_remote(:url => {:action => :ping_response}, :frequency => 0.5, :condition => "stop_polling == false" ) -%> Quoting Ezra Zygmuntowicz <ezmobius at gmail.com>:> Very cool! I finally figured out how to stop a > periodically_call_remote via rjs or js. Do it like this, in the view > where you render your periodic call: > > <script>stop_polling = false;</script> > > <%= periodically_call_remote(:url => {:action => ''update_results''}, > :frequency => 5, > :condition => "stop_polling == false") %> > > <a href=''#'' onclick="stop_polling=true">Stop Polling</a> > > > #Or if you need to tell it to stop from the controller via rjs: > > def stop_polling > render :update { |p| p.assign ''stop_polling'', true } > end > > > > And thats it, the periodic call will stop polling once the js variable > stop_polling is set to true. Of course you could also just set it to > true in the view but it depends on where you get the info that tells > you to stop polling. > > > Cheers- > -Ezra > > > On Aug 16, 2006, at 2:47 PM, mattp at digimonkey.com wrote: > >> 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 >> >> >> _______________________________________________ >> Backgroundrb-devel mailing list >> Backgroundrb-devel at rubyforge.org >> http://rubyforge.org/mailman/listinfo/backgroundrb-devel >>