A Blog on Ruby on Rails, Social Networking, Digital Marketing, Politics, and Other Thoughts.

Tag Cloud

Starling, Workling, God, and Whenever

Posted: January 10th, 2010 | Author: monolith | Filed under: Uncategorized | Tags: , , , , , , , | 4 Comments »

One of the problems with a new website is getting people to comeback to check for new content.  So I wanted to create an email reminder.  So that is what I’ll cover in this post… a background process that once in a while sends an email, reminding people to come back for some new content.

This is my first time going through this, so this is more about sharing what I learned than anything else.

The first thing to figure out is how to figure out WHAT to send.  That of course is basic Rails, and I leave that piece to you.  At a high level, I did this by creating a Reminder model and with it I look at when each person last logged in, and if there is new content of interest for the person – and of course, whether the person opted into receiving these reminders.  If there is something there, and the person has not logged in for at least a week, and a reminder has not been seen to this person for at least a week – then this person is due for a reminder.

If you want to see the code for that, look here:
http://github.com/monolith/commune2/blob/master/app/models/reminder.rb

Essentially, Reminder.users_with_reminders will now give me a list of people who need to get an email reminder.

So, how to actually use this information to send an email in the background?

Here is what this post will cover:

  • Starling and Workling background processing.
  • God gem to ensure the background processing is up.
  • Whenever gem and crontab for regularly scheduled events (triggering process to send emails).

Starling

Starling is a queuing server written as a ruby gem.  It was written by the folks at Twitter.  So, if it works for them, it probably works for you.  And it is easy to set up.

Why do you need a queue server?  Without it, you will hang your website until it goes through the entire list of people to be emailed and emails each and every one of them.

sudo gem install starling

If you are using Ruby Enterprise Edition, then you may want to create a symlink for Starling, something along the lines of the following (depends on where your REE is installed):

ln -s /opt/ruby-enterprise-1.8.6-20090610/bin/starling /usr/bin/starling

Simple.   Next…

Workling

Workling is your Rails API for interfacing with Starling.  You can use Starling directly, but this makes it a little easier.

script/plugin install git://github.com/purzelrakete/workling.git

You may want to watch this great Railscast on both Starling and Workling

http://railscasts.com/episodes/128-starling-and-workling

OK, now let’s create a little worker.  This is a piece of code, that when triggered, will run in the background, go through all the people who need to get a reminder, and email each.  All as a background process.

Feel free to create your own worker.  In the directory structure, workers should go under app/workers.  Here is my example:
http://github.com/monolith/commune2/blob/master/app/workers/mailings_worker.rb

Notice that this code utilizes ActionMailer (for deliver_dashboard_alert).  Nothing fancy here, assuming you have used ActionMailer before.

Also note that you should have config/workling.yml file.  Starling can be launched on different ports.  Keep this in mind in case you run into issues with ports.  The yml file tells Workling where Starling is launched. Your file should look something like this by default:

http://github.com/monolith/commune2/blob/master/config/workling.yml

So, let’s see if this works…

In these next steps we will test emailing using Starling/Workling.  Of course, this means your data must return a list of users to be emailed, your Worker need to be able to retrieve that list of users and then call ActionMailer to email each.  Assuming you have this code and data ready, let’s kick it off manually to make sure it works…

starling -d -P YOUR_APP_PATH/log/starling.pid -q YOUR_APP_PATH/log/ -p 22122

Notice the port used is 22122. Why this? Because if you look at your config/workling.yml file, that should be the port for your development environment. You can change it, just make sure whatever port you use is consistent with the workling.yml file (which you can change).

OK, hopefully that worked. If not, make sure you installed Starling correctly, make sure the path is right, and make sure the port is available (or pick another port that IS available – if you do use a different port, update workling.yml).

Now let’s launch Workling:

RAILS_ENV=development script/workling_client

Workling assumes development environment. This means you don’t need to use RAILS_ENV=development here, but remember you WILL need to use it in production (RAILS_ENV=production).

Hopefully that worked! If not, make sure config/workling.yml reflects the same port (in the right environment) that you used when launching Starling.

We’re all set. Let’s mail some stuff! Run this from your terminal:

RAILS_ENV=development script/runner MailingsWorker.async_reminders

(You could have also launched the console and then MailingsWorker.async_reminders from there).

NOTE: If you you created a different named Worker, call that one instead. Also note the use of async_ prefix on the method (you must use that… i.e. async_method_name).

So this should have worked. If not, check your Worker code to make sure it’s actually finding people to email and then emailing. If you’re not sure how to write code that emails, read up on ActionMailer and learn how to use it before trying this again.

God

Alright, so hopefully you made it here and everything works so far.  You probably noticed that if you have not launched Starling and Workling first, then MailingsWorker.async_reminders (or your equivalent of it) would not have sent any emails.  So, you always have to make sure Starling and Workling are up.  There are several ways of doing this.  One way is to set up monitoring with the god gem.

Once again, there is a great Railscast on this: http://railscasts.com/episodes/130-monitoring-with-god

sudo gem install god

Create a file to store details on what you want to monitor with god. You should name the file after your application, so, for me, that is commune2.god… and put it in your config directory.

Here is my file, copy and paste (ignore the thinking sphinx part unless you know what that is):
http://github.com/monolith/commune2/blob/master/config/commune2.god

Couple of things to note about this file, and these have to do with different environments. This is because I want to run god on both my development machine as well as production. Since I use different ports in each environment, I have some code in there to determine which environment I am in:


if RAILS_ROOT.include? "current"
RAILS_ENV="production"
else
RAILS_ENV="development" # assumption
end

That code is not pretty, and really it just looks at the directory structure to determine the environment. Nothing fancy.

Read the rest of the code there, particularly the Starling and Workling sections. Should be self explanatory. Make sure that the ports used in the Starling section look right, and of course, change the w.name and w.group values to something that better describes your application.

Now, let’s launch god. From the terminal window. This is how you do that: god -c directory_and_file_name… for me this is:

god -c config/commune2.god

Check if it worked:

god status

That should produce something that looks like this:

commune2:
commune2-starling: up
commune2-workling: up

So, this tells us that the god monitoring is up… not necessarily Starling and Working. To check if those are up:

god log commune2-starling

(change that to whatever it is you named your Starling monitoring process)

Hopefully you see something like the following (and same for the Workling process):

INFO: commune2-starling [ok] process is running (ProcessRunning)

If you got this far, then you are in really good shape!

Whenever

OK, so so far we set up Starling, Working, and made sure that they are always up with god. Another thing we should do is ensure that the server stars god on restart, and that it call that MailingsWorker.async_reminders (or your equivalent) periodically. The best way to achieve such recurring tasks is with the help of cron. But… you probably don’t want to deal with that yourself.

NOTE: For background tasks that are scheduled, it is better to use cron than a running daemon because the daemon eats memory all the time.

So, look here and install:
http://github.com/javan/whenever/

Once installed, take a look at my schedule.rb file, and adjust as needed:
http://github.com/monolith/commune2/blob/master/config/schedule.rb

Notice that once again there is some code in there to determine the environment. Nothing fancy, just enough to get by. Adjust as needed.

The Capistrano deployment code (below) will take care of updating the crontab in production. But here is a trick, which you may have realized already) to run it on your development machine as well (from your project folder): RAILS_ENV=development whenever –update-crontab YOUR_APP_NAME. For me, this is:

(you don’t need to do this… but it is nice to have Starling, Workling, and any scheduled tasks to run in development by default)

RAILS_ENV=development whenever --update-crontab commune2

Now, after you log into your development box, you can do “god status” and check that everything is up an running.

Capistrano

If you use Capistrano (as you should!) for deployment, here’s what you should add to the deploy file.
If you have not set up Capistrano, check out my previous post: http://www.terravetus.com/2009/10/setup-tutorial-for-a-rails-application-with-git-github-capistrano-ruby-enterprise-passenger/


namespace :deploy do
desc "Update the crontab file"
task :update_crontab, :roles => :db do
run "cd #{current_path} && RAILS_ENV=production whenever --update-crontab #{application}"
end
end

namespace :god do
desc "terminating god for commune2"
task :stop do
begin
run "god terminate commune2"
rescue => e
puts "Could not terminate god: #{e}"
end
end

desc "restarting god"
task :start do
run "god -c #{current_path}/config/commune2.god"
end
end

I hope this helped you. Enjoy!


4 Comments on “Starling, Workling, God, and Whenever”

  1. 1 dental hygienist said at 9:06 PM on April 19th, 2010:

    I’ve recently started a blog, the information you provide on this site has helped me tremendously. Thank you for all of your time & work.

  2. 2 Blogging to the Bank 3.0 Review said at 5:01 PM on February 16th, 2011:

    Finally a smart blogger…I adore how you might be thinking and writing!

  3. 3 Seo Google said at 8:30 AM on March 3rd, 2011:

    Hi there, just became aware of your blog through Google, and found that it’s truly informative. I am going to watch out for brussels. I will be grateful if you continue this in future. Lots of people will be benefited from your writing. Cheers!

  4. 4 Shelli Bondura said at 9:22 AM on March 3rd, 2011:

    I am not sure where you are getting your information, but great topic. I needs to spend some time learning much more or understanding more. Thanks for fantastic information I was looking for this information for my mission.

Leave a Reply