Client Submitted Form to Create a Cron Job on Rails - ruby-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.

Related

Timer on server side in Rails

What am trying to achieve is:
1. User pressess button and starts time-limited form.
2. Timer starts.
3. After X time when timer reaches 0 and user did not finish the form, rails create a record in database and do some session cleaning actions (Model.create and session.delete).
This timer will work like safety measure if user starts the form and then becomes unavailable (closes web brower or shuts PC).
Could you point to me to right direction? Where I should start? What language/framework should I use to do that?
You can use timestamps to record when something happened. Rails already has a great example of this in the updated_at and created_at fields.
You can re-use this concept to store when the user first started filling out the form, perhaps on the resource's new route, which usually coincides with the opening of the form.
As for performing the cleanup, you have two options that would could even both work together, depending on the situation:
If the cleanup isn't security-sensitive, you could have a timer kick off on the front-end and then send an AJAX request to the back-end when it expires.
If the cleanup isn't time-sensitive, you could run a task every few minutes or so, which performs the cleanup on any forms that haven't been cleaned up yet. It would look at the timestamps to determine this.
Aside from those suggestions, we'd have to know more about your use cases to answer more questions.
Is the cleanup time-sensitive?
Is the cleanup security-sensitive?
There are more options - you could run the task more granularly or more securely.
Tight timing
One option if your timing is very tight (down to seconds) is to implement both options above, and in addition the following functionality:
Use ActionCable to keep a web socket open with the user. Periodically have them ping the server to check their status.
In a before_filter, probably in ApplicationController, check first if they have permission to continue the action, i.e. the timestamp hasn't expired yet. If the timestamp has expired, and the cleanup hasn't been performed yet, then perform it now.
Limitations of this approach:
If the user closes the website entirely, the cleanup is not going to happen until the next cleanup task happens.
There are vulnerabilities on the front-end. The user can disable the front-end checks, and then avoid submitting the form, which will delay the cleanup in the same way as #1.

Update view after background job finishes in 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.

Rails 3.1 - Events based on time

I have an 'Event' model that contains a list of events along with their start time.
When the current time reaches the event start time, I would like to fire some action.
In other words, I want to do something whenever an event starts.
How can I accomplish this in Ruby / Rails ?
There are two ways to deal with this. Either you write a script that checks the Events permanently and triggers some action when the event date is in the past or you use a gem for that. I would suggest you to watch some of the background job screencasts that deal with your problem:
http://railscasts.com/?tag_id=32

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.

How to go about sending email x hours after a user signs up in Ruby on Rails?

How would I go about sending an email to a user, say, 48 hours after they sign up, in Ruby on Rails? Thanks!
As Joseph Daigle mentioned, you need to obviously record the exact date and time the user registered. After that, you need a cron running every certain number of minutes (every hour, for example) checking to see if there's any new users whose registration time is greater than 48 hours, send a mail to said user and mark that user as already emailed, so you don't email them again.
As per the actual mail sending, check out the following documentation page:
http://wiki.rubyonrails.org/rails/pages/HowToSendEmailsWithActionMailer
It has all you need to know to send mails with RoR.
I recommend that you use the latest version of BackgrounDRb to handle this. You can read about BackgrounDRb here: http://backgroundrb.rubyforge.org/
In order to queue a message for later delivery, the BackgrounDRb client code (in your application model's after_create callback, maybe) could look something like this:
MiddleMan(:email_worker).enq_send_email_task(:message => #message,
:job_key => "notify1",
:scheduled_at => Time.now + 48.hours)
You'd have to build a BackgrounDRb worker to handle sending the email:
# RAILS_ROOT/lib/workers/email_worker.rb
class EmailWorker < BackgrounDRb::MetaWorker
set_worker_name :email_worker
def send_email_task(message)
# ... Code to send the email message
end
end
Note that in order to use BackgrounDRb in this way, you have to use persistent job queues, so make sure you run the migration included with BackgrounDRb to set up the persistence table in your application.
BackgrounDRb is started separately from Rails (mongrel, apache, etc) using 'script/backgroundrb start', so make sure that you add the daemon to whatever process monitoring you're using (god, monit, etc) or that you create an /etc/init.d script for it.
First you're going to need a running daemon or background service which can poll your queue (probably from in a database) every few minutes.
The algorithm is pretty simple. Record the time of the user event in the queue. When the daemon checks that item in the queue, and the time difference is greater than 48 hours, prepare the e-mail to send.
You can queue jobs with a delay using async observer. Ideally, anything you have that isn't known to be instant (or very close to it) all the time should pass through something like that.
I wrote a plugin called acts_as_scheduled that may help you out.
acts_as_scheduled allows you to manage
scheduled events for your models.
A good example of this is scheduling
the update of RSS Feeds in a
background process using Cron or
BackgroundRB.
With acts_as_scheduled your schedule
manager can simply call
"Model.find_next_scheduled()" to grab
the next item from the database.
How I would approach this is by creating a scheduling controller, that will query the database for the next_scheduled and then use a mailer to send the message. The you set up a Cron Job to call the controller periodically using WGET or CURL. The advantage of the Cron/Controller approach is that no further infrastructure or configuration is required on the server and you avoid complicated threading code.
I think I'd be inclined to store the need for the email and the earliest time after which it should be sent, somewhere separate, then have my things-to-do task look at that. That way I only have to process as many records as there are emails to be sent, rather than examine every user every time, which would either get tedious or require an otherwise probably unnecessary index. As a bonus, if I had other tasks to be performed on some sort of a diarised basis, the same construct would be useful with little modification.

Resources