Search code examples
ruby-on-railsruby-on-rails-3ruby-on-rails-4delayed-job

Rails - Delayed Job - How to rerun a method indefinitely.


I am using delayed job to run a specific method in the background, and I need to keep running this method indefinitely, until it is stopped by the user. I have this set up as follows:

I have a button in my view which calls a controller method as follows:

My view:

  <%= form_tag(:controller => 'home', :action => 'start') do %>
  <%= submit_tag "Start Checking for new Data", :class => "btn btn-success btn-lg btn-start" %>
  <% end %>

My Controller:

def start
    if current_user
        begin
         Poller.delay.do_something(client) 
         flash[:notice] = 'Polling Started'
        rescue
         flash[:error] = 'Issue connecting to API. Please try again later.'
        end
       redirect_to :back
    end
  end

How can I allow the user to Start checking for new data by calling the start method over and over? Also, how can I allow them to Stop checking for new data by calling a method which will stop calling the start method?


Solution

  • A first step would be to have your Poller job check some model attribute on each iteration looking for some signal to end it's loop. Rather than trying to interrupt the Poller let it finish the current iteration but check if it should continue before looping.

    However there are still problems with this pattern overall and I encourage you to reconsider background jobs which loop forever.

    • This job will block a worker and prevent that worker from running a Poller for any other user until the current Poller finishes.
    • The user may not choose or be able to send a stop signal, you probably want to stop anyway after some limit.
    • It seems unlikely that you really want to poll whatever endpoint you are using as fast as possible. Rather than spin a worker waiting during each iteration it would be nice if that worker were available to handle other jobs instead.

    A better solution might be to have your Poller job run once and then enqueue a copy of itself when it finishes if the polling should continue. Your worker can then interleave Poller jobs from many users. Much like above each job can check some model state or method to determine if it should enqueue another poll action or not. Depending on how you run those jobs it may also be easier to schedule future iterations with some delay to throttle your polling.