How to show the resque worker status to the end user? - ruby-on-rails

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.

Related

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.

Scheduling events in Ruby on Rails

SO sorry if this is a duplicate, I tried searching for this but wasnt sure what search terms to use and didnt really find anything.
I have a Ruby on Rails app that will be used to send text messages out to users that contain a link to a multiple choice question probably using clickatell. The questions have a date and time associated with them. I want to make the ruby on rails app automatically send those SMS messages to the users' phones on those specified dates.
I don't really know how one would go about doing this. Can anyone point me in the general direction of a a way to schedule events like this in ruby on rails. I don't need an exact solution, maybe if someone could just clarify what exactly this is called so I can find some resources on line.
thanks
It seems the sending out your questions is not reoccuring? In this case I would not do this via a cronjob. I would do this via: https://github.com/bvandenbos/resque-scheduler
So whenever a question is getting scheduled you just add it to the delayed queue and resque-scheduler handles moving them on the correct working queue when its time has come.
This way you don't have to worry about some sort of polling cronjob, this will be done by resque-scheduler automatically. You also get asynchronous handling of sending out the SMSes via resque for free. So if you have to send lots and lots of SMS you can run them in parallel.
So it would go like this:
when a question is saved, you queue a message on the delayed queue in the future for sending out the question
when the date comes up, the message is moved onto 'ready to send'-queue, which is in charge of gathering all the users the question needs to be sent to.
for each of those users you create another message on the 'ready to send'-queue
the 'ready to send'-queue will then send out the actual SMSes
You then can run many workers on the 'ready to send'-queue and have the SMSes be sent out in parallel. You also get error handling for free with resque, it gahers all messages that resulted in an exception in a 'failure' queue, which you can then debug or reschedule again
You could use whenever to schedule events.

How to have users create scheduled tasks in rails app deployed on Heroku

I have a rails app deployed on Heroku. I want to add a feature that enables users of the app to set a reminder. I need some way for the app to schedule sending an email at the time specified by the user.
I have found numerous posts referring to using delayed_job for this, but none of the write-ups / tutorials / etc. that I have found directly address what I am trying to accomplish (the descriptions I have found seem more geared towards managing long-running jobs that are to be run "whenever").
Am I on the right track looking at delayed_job for this? If so, can somebody point me towards a tutorial that might help me?
If delayed_job is not quite right for the job, does anybody have a suggestion for how I might approach this?
The most typical way of handling this is to use a cron job. You schedule a job to run every 15 minutes or so and deliver any reminders that come up in that time. Unfortunately, heroku only allows cron jobs to run every hour, which usually isn't often enough.
In this case, I'd use delayedjob and trick it into setting up a recurring task that delivers the notifications as often as necessary. For example, you could create a function that begins by rescheduling itself to run in 10 minutes and then goes on to send any reminders that popped up in the previous 10 minutes.
To view delayedjobs send_at syntax to schedule future jobs check here: https://github.com/tobi/delayed_job/wiki
ADDED after comments:
To send the reminder, you would need to create a function that searches for pending reminders and sends them. For example, let's say you have a model called Reminder (rails 3 syntax cause I like it better):
def self.find_and_send_reminders
reminders = Reminder.where("send_at < ? AND sent = ?", Time.now, false).all
reminders.each do |r|
#the following delayed_job syntax is apparently new, and I haven't tried it. came from the collective_idea fork of delayed_job on github
Notifier.delay.deliver_reminder_email(r)
#I'm not checking to make sure that anything actually sent successfully here, just assuming they did. may want to address this better in your real app
r.update_attributes!(:sent => true)
end
#again using the new syntax, untested. heroku may require the old "send_at" and "send_later" syntax
Reminder.delay(:run_at => 15.minutes.from_now).find_and_send_reminders
end
This syntax assumes you decided to use the single reminder entry for every occurence method. If you decide to use a single entry for all recurring reminders, you could create a field like "last_sent" instead of a boolean for "sent" and use that. Keep in mind these are all just ideas, I haven't actually taken the time to implement anything like this yet so I probably haven't considered all the options/problems.
Check out the runt gem, may be useful for you: http://runt.rubyforge.org/
You can use delayed_job's run_at to schedule at a specific time instead of whenever.
If your application allows the users to change the time of the reminders you need to remember the delayed_job to be able to update it or delete it when required.
Here is more details.
It's good to avoid polling if you can. The worker thread will poll at the database level, you don't want to add polling on top of polling.

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