Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trigger the reloading of a page after a background job

I have a rails 4 application, that is doing a background calculus. So the user press a button and it launches a background job for the long calculus (using delay_job) and arrive on a waiting page. Despite the fact that the calculus is done asynchronously, I would like to find a way to warn the user and automatically reload it page once the calculus is finish.

I have looked at several solutions :

  • Faye or private_pub => I can't afford to use another server for this very specific job
  • ActionController::Live => I am not sure how to trigger the action once the job is finished
  • Polling => best solution for the moment, but I expect to find something that is less greedy than polling

If you have any smart solution for this problem, or any advise for my limitation in the listed ideas.

like image 347
Raphael Pr Avatar asked Nov 11 '22 11:11

Raphael Pr


1 Answers

I'll explain how this works for you


HTTP

When you send the request to Rails, your browser doesn't have any way to "listen" to what happens to anything other than a direct response. The HTTP request is "sent" & doesn't have any mechanism to wait until the asynchronous process is complete

Your job is to give your app a "listener" so that your front-end can receive updates as they are generated (out of scope of HTTP), hence the websocket or SSE stuff

We've set up what you're looking for before, using Pusher


"Live"

Achieving "live" functionality is what you need

This basically means keeping a request open "perpetually" to the server; listening to any of the "events" the server sends back. This is done with JS on the front-end, where the client will "subscribe" to a channel (typically a user-centric one), and will then have all the data sent to it

We used a third-party system called Pusher to achieve this recently:

#GemFile
gem "pusher", "~> 0.12.0"    

#app/controllers/message.rb
def send_message
    public_key = self.user.public_key
    Pusher['private-user-' + public_key].trigger('message_sent', {
        message: "Message Sent"
    })  
end

   #app/assets/javascripts/application.js
   pusher = new Pusher("***********",
     cluster: 'eu'
   )

   channel = pusher.subscribe("private-user-#{gon.user}")
   channel.bind "message_sent", (data) ->
    alert data.message

Hope this gives another option for you

like image 170
Richard Peck Avatar answered Nov 14 '22 21:11

Richard Peck