2

(This question is a follow-up to How do I handle long requests for a Rails App so other users are not delayed too much? )

A user submits an answer to my Rails app and it gets checked in the back-end for up to 10 seconds. This would cause delays for all other users, so I'm trying out the delayed_job gem to move the checking to a Worker process. The Worker code returns the results back to the controller. However, the controller doesn't realize it's supposed to wait patiently for the results, so it causes an error.

How do I get the controller to wait for the results and let the rest of the app handle simple requests meanwhile?
In Javascript, one would use callbacks to call the function instead of returning a value. Should I do the same thing in Ruby and call back the controller from the Worker?

Update:
Alternatively, how can I call a controller method from the Worker? Then I could just call the relevant actions when its done.

This is the relevant code:

Controller:

def submit
  question = Question.find params[:question]
  user_answer = params[:user_answer]
  @result, @other_stuff = SubmitWorker.new.check(question, user_answer)
  render_ajax 
end

submit_worker.rb :

class SubmitWorker
 def check
   #lots of code... 
 end
 handle_asynchronously :check 
end
Community
  • 1
  • 1
Ari
  • 1,974
  • 19
  • 30
  • 1
    You don't make the controller wait, you have the DJ trigger an event that pushes a notification to the browser. – mu is too short Aug 06 '13 at 21:54
  • @muistooshort, i should bypass the controller and pass all the variables, etc. from the Worker to the view? – Ari Aug 06 '13 at 21:57

2 Answers2

4

Using DJ to offload the work is absolutely fine and normal, but making the controller wait for the response rather defeats the point.

You can add some form of callback to the end of your check method so that when the job finishes your user can be notified.

You can find some discussion on performing notifications in this question: push-style notifications simliar to Facebook with Rails and jQuery

Alternatively you can have your browser periodically call a controller action that checks for the results of the job - the results would ideally be an ActiveRecord object. Again you can find discussion on periodic javascript in this question: Rails 3 equivalent for periodically_call_remote

Community
  • 1
  • 1
Matt
  • 13,948
  • 6
  • 44
  • 68
  • The first link looks like it also involves checking periodically from the view. I guess there's no simpler way then... – Ari Aug 07 '13 at 20:32
  • The first link includes a few gem choices to do some of the hard work for you, but I would personally recommend you keep things as simple as you can. Find a way to allow your page to periodically check if the results of the job have been created in the database, and then act on those results. Give it a go, and if you get into any trouble - start a new question! Best of luck to you. – Matt Aug 07 '13 at 22:53
0

I think what you are trying to do here is little contradicting, because you use delayed_job when do done want to interrupt the control flow (so your users don't want to want until the request completes).

But if you want your controller to want until you get the results, then you don't want to use background processes like delayed_job.

You might want to think of different way of notifying the user, after you have done your checking, while keeping the background process as it is.

halfer
  • 19,824
  • 17
  • 99
  • 186
sameera207
  • 16,547
  • 19
  • 87
  • 152
  • the idea of using it was to avoid slowing down other users visiting the app at the same time. is there a simpler way to do that? – Ari Aug 07 '13 at 00:21
  • @Ari, rails by default is single threaded (http://stackoverflow.com/questions/1388979/are-rails-controllers-multithreaded-thread-exclusive-in-controllers), so because of that, if one request stops, all the others will also stops. If you read the answer for the above question, it has some nice workaarounds proposed – sameera207 Aug 08 '13 at 07:21