I generate xls-file in background with help of delayed_job gem. After this I would like to send file to the user. Is there some way to call send_file method outside of controller in delayed_job class?
If you are backgrounding a task to delayed_job, then the user's request will no longer exist. If it does still exist, then you don't need to background the task at all (because it defeats the whole purpose of backgrounding).
My recommendation is to save the file off to disk with a corresponding database record once delayed_job generates it. While the user waits, have Ajax occasionally asking the server if the file is ready. When it is ready, use Ajax to make a new request for the file, display a download link, or whatever works best.
Related
I got an application that creates loads of PDF documents which, sometimes take some time to create, hence I moved all the PDF creation to a resque background job. However, some PDFs need also to be sent out by mail which now is a problem because I don't know how to tell the mailer to wait for the PDFs to be created.
Before I had this:
#contract.create_invoice
ContractMailer.send_invoice(#contract).deliver
Now I have this:
Resque.enqueue(InvoiceCreator, #contract)
ContractMailer.send_invoice(#contract).deliver
So ContractMailer always fails because the pdf is not yet created. Anyone has an idea how to solve this elegantly?
Thanks!
I have a controller with three actions: index, iframe, and result. The way it works is the user visits the index action via GET request. This renders a view that includes a form. The form is simply a button that POSTs to result. My result action simply renders a page that includes a jQuery progress bar and an iframe, the content of which is the iframe action. The iframe action does some long-running processing and eventually returns the result to the result view. (The whole reason I need to do this in an iframe is so the result action returns quickly with a progress bar so the user doesn't think the application crashed.)
Previously the form consisted solely of a button that POSTed to result. In this scenario, the iframe action downloads a ~100MB file from a static URL and does some processing on it, then updates the parent page (result) with the result of the processing.
Now I need to provide the option of uploading a file to process instead of always using the static URL to download from. Basically, if a user provides a file, use that file; otherwise, use the static URL. I have modified my form to accept a file upload and this part is working fine. My problem is how to pass this uploaded file, which is ~100MB, from result to iframe. It is far too big to put in the session. The uploaded file does not need to be saved between runs.
In addition to the implementation detail, you should update your question with a bit more of the background of the problem - what kind of files are you uploading? What kind of processing do you do? What is the purpose of the system from an end-users perspective? It'll help people understand the problem you're trying to solve.
I'm making some assumptions about the purpose of your system here, but here's what I'd do:
I'd upload files and store them in the file system, and also create a new record in a database table indicating the location of the file within the system, and wether the file is "processed" or not. You can use the Carrier Wave gem for this: https://github.com/carrierwaveuploader/carrierwave
I'd then use some kind of background job tool to do the actual processing. So, when a file is uploaded, you add it to the 'queue of stuff to be processed', then return a message to the user saying "the job has been added to the queue for processing and will be finished soon". The ID of the row you saved in the database table can serve as the identifier for which file needs to be processed. Once it's processed, you update the "processed" column in the database to be true. There are several gems to choose from when it comes to background jobs - one popular one is SideKiq - http://sidekiq.org/
At that point, it's basically up to you in terms of how smooth you want to make the process from your end user's perspective. A simplest case would be:
When you return the message "the job has been added to the queue for processing and will be finished soon," you could also say "It should be complete within a few mintues. Refresh this page to see if your job is complete". Each refresh, if the processing is complete, you'd let them know.
A more sophisticated way would be: Once the "job has been added to the queue" page is shown, you could display a timer counting how long it's been, and use a javascript timer to regularly make AJAX requests to the server every couple of seconds to check if the job has been completed. Once the job has been completed, update the page to indicate that, using AJAX.
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.
I have a Grails app that downloads a file that's generated from a database query that takes about a minute. How can I implement a sort of hourglass (or something prettier) so the user knows the request is being processed ?
The corresponding link calls a controller method that does the processing and uses the response object.
I think you want to do something like a spinner notification while an operation is being processed.
you can check this out
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.