Update view after background job finishes in Rails - ruby-on-rails

I am new to Rails. I have a background job that runs and takes about a minute. I want to display message on the view after the job is complete. How would I do that?

Unfortunately there is really no simple solution for this one, I'll give you few ideas how you could handle this problem.
Simplest solution would be to just send an email to user when job finishes. I know this is not what you asked for but this is a quick and easy way to inform user some long running process is done.
You could make an API endpoint that returns state of the task and then use javascript to poll that endpoint every X seconds. Exact implementation of this varies depending on what that background job is.
You could use something like websocket-rails to open 2 way connection with the browser. This way you could send message to the browser to update view once the background job is done.

Related

Async rails action with responses

Basically, what i need is:
When user press button "Parse" it sends request to the server (using ajax) and execute controller action with loop. It must be done asynchronous and user must get response how many percentage is finished (like loader...)
What is the best method of implementing this?
The most difficult task with what you're describing is updating the loader to show the right percentage. If you can do without, I suggest you do. If you really want a loader because the parsing takes a lot of time, I can see 3 options:
Use websockets to send the percentage to the user once it is updated. Rails will be including Actioncable in Rails 5 to easily do this but you can try it out now: https://github.com/rails/actioncable
Use a third party service such as https://pusher.com/ to easily implement this without managing your own websocket server
Or save the percentage in Redis and create an endpoint that you'll ping every second or so to update the loader. It feels a bit hacked but sometimes it's enough.
Good luck!

How to dispaly a holding screen whilst ActiveJob retrieves lots of data from an external API

I have an application that makes API requests to salesforce using restforce.
Specifically the application finds a contact object, returns IDs for all related objects and then pulls the full record for every related object based on their ID.
This takes a long time for two reasons:
There are a lot of request to an external API, usually takes a few fractions of a second for each to reply and for some there can be +500 individual requests.
There is often a large amount of data being pulled back via each request.
All requests currently fall within the salesforce rest API limits but I'm getting timeout errors from my development server as it can take 5+ minutes for some of these requests to process.
Rails 4.2 - How best to handle this?
My question is how do I best get rails to handle this?
I can fire the API requests either from the controller (which definitely violates the skinny controllers) or from the view (via helper methods, which seems like a dodgy hack).
Ideally I'd like to get it running in a background job, but i'm unsure if I can just include all the authentication and other methods in a job in the same way I can include helper methods?
Even if I could get it to work in a background job, I'm unsure what best practice might be for the user experience. Ideally I'd like to route them to a page telling them to "hang tight, go get a coffee" with a progress bar, and then auto route them to the final page once the request is complete...
But I'm unsure how to generate a temporary display until a job has been completed?
Could anyone recommend any gems or strategies that might help me digest this problem?
You should definitely use a background job for this.
Give a database object to the job, which it will update to signal that is has finished, and maybe from time to time to indicate progress.
On the user side, simply tell them that the background job is working, with eventually a progress indicator, and display the result once the database object giving to the job tells you it's ready.

How to show the resque worker status to the end user?

I'm using Resque in my application to run background jobs. The background jobs are taking a considerable amount of time to complete and thats why I want to display the status of the jobs to the end user so that they know by when the tasks will be completed. I am having a difficult time to find a solution to this problem, any help would be highly appreciated. Thanks!
Have you looked into the resque-status gem? The gem will give you a hash that you can query for the status of the job. Next, you'll need to figure out the best way to notify the user.
Personally, I think the most straight forward method would be to just send an email when the job is complete. If you desire to notify the user in their web browser, you'll probably need to implement some sort of pub/sub system that fires off a notification to alert the browser. This is reasonably complicated, so just sending an email is probably your best option.

Client Submitted Form to Create a Cron Job on Rails

Okay I decided to improve on what I am asking for help with verse just opening a new question on this. I believe I can accomplish the below if I know of a way that when a client submits a form on my Rails app a cron job is run, where the time for the cron job is selected by the user from a drop down menu. Is there a way to do this, I have been googling around for ideas but haven't found one.
Old Question
I am attempting to develop a system that would allow a user to upload a movie to my site and then have it played back at a certain time. The movies would be continuously streamed, so that at a certain time say after an hour, the next movie in the queue would play. I am wondering is there a gem or script that already does this? Or what is the best way to go about doing it, I thought doing it with jobs like cron or delayed-job, but I don't think that's the most efficient way to do this. Any advice would be appreciated.
p.s. I think a simplier way to explain it is, on YouTube you can queue up videos to be played, so could one do something similiar in rails, this would help towards my problem.
If the user gets to decide the exact time of playback, you could use the rufus-scheduler gem.
Plug in your Time obtained from the user like so:
scheduler = Rufus::Scheduler.start_new
scheduler.at #user_defined_time do
some_method
end
Your some_method could work in tandem with a socket.io wrapper like Juggernaut, which would send a message to the user's browser, which would execute some JS that would fetch the video and play it.
What you could do with this is basically sit around with your browser window open, and when the scheduled time is reached, the browser would fetch the appropriate video and play it.
If you need to implement a video queueing system, you could just enable users to queue up the videos they want to by ID, and then call the next video in the queue via means for a callback function which is triggered when the video has ended. The callback would query the database for the next video in the queue, fetch the video, and play it.
I've used the extremely popular Whenever on projects that rely heavily on scheduled tasks, and it's great. It gives you a nice DSL to define your scheduled tasks instead of having to deal with crontab format. From the README:
Whenever is a Ruby gem that provides a clear syntax for writing and deploying cron jobs.
Example from the README:
every 3.hours do
runner "MyModel.some_process"
rake "my:rake:task"
command "/usr/bin/my_great_command"
end
every 1.day, :at => '4:30 am' do
runner "MyModel.task_to_run_at_four_thirty_in_the_morning"
end
Put your user defined parameters in above query. thats it.
I don't believe you even need to do the background stuff for just front-end scheduling.
Need not to even go for Juggernaut or any Cron Job thingy.
This all can simply be achieved by using JavaScript.
You can either use javascript's setTimeout() and clearTimeout() functions or add a sleep() before your ajax call.
here are the steps:
You load the first movie or just the page.
Make an ajax call within the setTimeout function.
Note: don't forget to assign the setTimeout() to a variable so that you can do clearTimeout(the_variable).
here is the detailed usage: http://www.w3schools.com/js/js_timing.asp
setTimeout works as setTimeout(javascript_statement, milliseconds) ... these milliseconds should be the total time of the current movie or whatever time that's being set by the user subtracted from the current time which gives you milliseconds left to be played.
Send the current movie id in this ajax request, so that on server you can calculate which movie is to be played after the movie just played... by fetching the last movie played with this sent movie-id parameter.
I also believe you'd require some functionality like, only play the next movie when the current movie ends. So basically you can also replace the setTimeout() function for making the Ajax call with the movie-players function. Just make an ajax call to server when the movie-player completes playing the current movie... again sending the current movie-id in the request.
If even after the completion of current movie, you want to wait for the appropriate time to start the movie, you need to make use of periodically_call_remote which sends a ajax requests after a set number of seconds.
And once on server, i.e. in your controller where you handle that ajax request, once you make sure you need to show the movie now, just replace the player container with the partial containing the player and the link to the newmovie with autoplay-on-load set to true.

Background processing in Rails

A certain function in my controller takes a lot of time to process (heavy db work) . So when my user clicks on "submit" on the form he has to wait for the process to complete which is quite long. Is there any way that on "submitting", the user is redirected to the next view without any delay while the processing continues in the back-end without making the user wait ?
Thanks & Cheers !
When the user's request is made, queue up the job and then redirect the request where you want it.
There are two popular Ruby Gems for job processing:
Delayed Job
Resque
Delayed job is probably the easier to setup since it does not require Redis.
For things like this, I usually dump things into a database queue, and then use a cronjob to actually run it.
For instance, say I had to send out an email to all the clients using the software. I'd put the message into a database table, along with some information about who should get it, and then a cron job would actually do the sending.
It sounds to me that you need to fork the process that takes so long.
For example:
fork { "this code is being ran in background" }
The problem is that this code won't work nice with sql since the connection is not persistent. To handle this problem I've been using the spawn plugin for a while with excelent results.

Resources