Douglas F Shearer

Cron Jobs in Ruby on Rails


Attention!

It has come to my attention that this plugin is no longer available from it’s original source. I have made it available on Github.

In place of steps 2 and 3 below you can download the tarball and unpack it to your vendor/plugins directory.

Let me know in the comments how this goes, thanks.

Back to the action

Sometimes you need some precess to run at set time intervals, independent of the request-response cycle a standard web server. Things like (as I did) polling Flickr to see if you’ve added any new images to your account, or looking at a to-do list to see if any email reminders are due to be sent out.

Cron jobs under Unix are a great answer to this , but you have the problem of these being:

  1. Particular to Unix and Linux systems.
  2. How do you access your active-record models that make up your Rails app?

Enter Kyle Maxwell’s Daemon_generator plugin, a simple way to create and control daemons that run your own code within the Rails Environment.

It took me a while to figure out how to get it all set up, so I decided to write a guide to help people get to grips with it.

OK, here we go…

  1. Install the Daemons Gem on your system using the command:
    sudo gem install daemons
  2. Navigate to the root of your rails app, install the daemons_generator plugin in your app using the command:
    ruby script/plugin install http://svn.kylemaxwell.com/rails_plugins/daemon_generator/trunk
    See the the top of this article for the new download location.
  3. Unfortunately this will be installed in your vendor/plugins folder as trunk, so change the name of this to daemon_generator so it’s easy to see at a glance what it is:
    mv vendor/plugins/trunk vendor/plugins/daemon_generator
  4. Now you can create your first daemon. I’m going to call mine test:
    ruby script/generate daemon test
    That should create a bunch of files, including lib/daemons/test.rb, which will hold your actual code. If you have a look at this, it should be fairly self-explanatory where you put your own code and how you set the time interval. Leave this unchanged for the moment, just to see it in action.
  5. Start the daemons with the command:
    ruby script/daemons start
  6. Look at the production log, you should see output similar to the following:
    dougal@tempy:~/test123$ tail -f log/production.log 
    This daemon is still running at Thu Nov 09 00:33:54 GMT 2006.
    This daemon is still running at Thu Nov 09 00:34:04 GMT 2006.
    This daemon is still running at Thu Nov 09 00:34:14 GMT 2006.
    It might seem strange to be looking at the production log, daemons run in production environment by default as they can be run separately from your web server (The we server doesn’t even have to be running to get this to work). You can of course change the environment at the top of lib/daemons/test.rb should you wish so for testing purposes.
  7. Stop your daemon with the command:
    ruby script/daemons stop

Having Trouble?

This plugin is no longer maintained by the original author. However, commenters have been kind enough to suggest fixes to problems. See Rob Lucas’s comment in particular. I will of course accept patches and fixes, and apply these to the repository.

Wrapup

That’s it, you created, run and halted your first daemon! More commands for controlling daemons can be found in the readme, and the complete source in Kyle’s SVN repository.

Hope that helped some people out. If you have any questions or problems leave a comment and I’ll hopefully see you good.

Screencast

You can now see Daemon Generator in moving pictures, courtesy of Ryan Bates’ Railscasts.

Tags

, , .

November 08 2006 23:42 | Posted in Coding | comments (22)
 

Comments


Gravatar

Brent

December 13 2006 21:01

Is there an explanation of the options in daemons.yml anywhere?

Gravatar

Douglas F Shearer

December 21 2006 22:02

There is no documentation for the code in the generator itself at all, but I'll take a look as to what it does and get back to you on that one.

Gravatar

Brent

January 04 2007 16:09

I left the same comment on Kyle's page and he pointed me to http://daemons.ru...

Gravatar

Douglas F Shearer

January 04 2007 16:25

Cheers Brent, that'll tech me to look in the Rdoc first!

Gravatar

John Houston

April 02 2007 23:37

Please Help.

I did just what you instructed.. but when I run the script I get this...

ruby script/daemons start
script/daemons:2:in ``': No such file or directory - script/../lib/daemons/test_ctl start (Errno::ENOENT)
from script/daemons:2
from script/daemons:2:in `each'
from script/daemons:2

Any Idea why I get this error?

Gravatar

Douglas F Shearer

April 02 2007 23:48

Hi John. If you drop me an email at dougal DOT s AT gmail DOT com I'll email you back there.

Any other details you can provide (even a full paste of your terminal from when you started) will help me track the problem down. Should be able to get you sorted out.

Gravatar

lucian

April 05 2007 18:46

Hi,

I get the same error as John above did ... how can i fix it .. i run mongrell on my machine.
Any help is appreciated.

Thank you

Gravatar

Douglas F Shearer

April 06 2007 01:06

OK, I looked into it. In the daemons script, it looks for every *_ctl file, and passes on the command line argument for it.

For some reason, when you are running 'ruby script/generate daemon test' the test_ctl file is not being created, either that or you are not using this generator.

I just tested by downloading the latest version of the gem, and the latest plugin into a new rails app. I followed the instructions above, and everything ran fine.

Let me know if this helps in some way.

Gravatar

Larry Erickson

May 31 2007 16:41

I am still getting the same error as John and Lucian above. I have the latest versions as of today. It looks like the test_ctl file is being created. Any help would be appreciated.

Gravatar

krunkster

June 05 2007 05:45

About the error above, try editing the config/daemons file and change:
"/../lib/daemons/*_ctl"
to: "../lib/daemons/*_ctl"

That worked for me... unfortunately dameon_generator does not work on Windows environments apparently.

Gravatar

Douglas F Shearer

June 05 2007 12:49

Sorry I've not replied to queries in a while.

Krunkster - It looks like you may have hit the nail on the head! The preceding slash (/) would definitely cause things to be created in the wrong place on certain platforms.

As for running this on Windows, I would think it is a *nix only situation.

I'll blog about this later in the week, but recently I've been running cron jobs as a standard unix cron task, called script/runner. Much easier to administer, though only really useful if you have root access to the machine in question.

Gravatar

Andrew

August 29 2007 18:27

I am trying to run this under InstantRails on Windows and it looks like I am out of luck!

Anyone have another suggestion? I am still prototyping and will move a "real" environment but was hoping to make some headway on my persistent process to look for users that have not checked in lately.

Ideas and thoughts appreciated!
Andrew

Gravatar

Shannon

October 09 2007 21:05

How do I tap into the "scheduling" aspect that CRON is known for?

In other words, if I want a action to fire at 5:00am daily--- and another action to fire every other friday, how would I do that?

I want to stay away from OS specific things (like CRON) -- otherwise I would use that & script/runner.

Any ideas?

Thanks!
Shannon

Gravatar

Nico

December 12 2007 20:38

Hi!

Anybody tried sending email from the deamon?

I try to send an html mail using the Actionmailer with the following code:

email = SiteNewsNotifier.create_new_messages( new_messages, email_addresses )
email.set_content_type("text/html")

SiteNewsNotifier.deliver(email)

In my production log it says the mail was sent and also the full html and mail details are shown, but the mail is not delivered and any following code in the deamon is not executed. The above code works fine when called from within a controller action.

Any idea what could be the problem?

Nico

Gravatar

David

April 30 2008 14:27

Hi, thanks for all your help so far. I'm having a problem with part 6. My production log remains unchanged while the test daemon is running, and in the log for test.rb.log it's giving me a bunch of errors. What gives?
I'm getting...
<MissingSourceFile: no such file to load -- fast_xs>
<NoMemoryError: failed to allocate memory>
<SystemStackError: stack level too deep>
<fatal: exception reentered>
<LoadError: no such file to load -- active_support>
<Gem::Exception: can't activate activesupport (= 1.4.4), already activated activesupport-2.0.2]>
<NameError: uninitialized constant Rails>
<MissingSourceFile: no such file to load -- utf8proc_native>
<MissingSourceFile: no such file to load -- fast_xs>
...any idea where I could start trouble shooting?

I found fast_xs on Ruby-forge. Installed that (I think) and still no luck.

Help!

Gravatar

Rob Lucas

May 01 2008 17:14

Hi,

I'm having problems with the same line discussed above:

Dir[File.dirname(__FILE__) + "/../lib/daemons/*_ctl"].each {|f| `#{f} #{ARGV.first}`}

However, this line appears to be correct on my system. E.g this will actually return the path "script/../lib/daemons/test_ctl":

Dir[File.dirname(__FILE__) + "/../lib/daemons/*_ctl"].each do |ctl|
puts ctl
end

If I change it as suggested above (to "../lib/"), it returns nothing at all.

The problem is that, even though it is clearly returning the correct file, I get ": No such file or directory" when running "ruby script/daemons start", which is evidently totally bizarre.

This, however, works:

ruby lib/daemons/test_ctl start

Is there some peculiarity with the Dir class perhaps? Anyone else seen similar behaviour?

Cheers,

Rob.

Gravatar

antipode

July 24 2008 15:12

@rob and @david, I had the same problem and it was solved by:

gem update

...
Updating daemons
Successfully installed daemons-1.0.10
...

(I previously had daemons-1.0.9)

Gravatar

Arman Imtiaz

August 07 2008 08:12

Production log is not updating :(
Having same problem as david said earlier. i've tried to update gem, but its already the latest version. Please help.

Gravatar

nron

August 21 2008 18:44

Those having problems w/ missing source files, etc.
The most likely reason is that you have entries in your environment.rb which won't load correctly from a non-root directory. Also, make sure you load the config/boot options. Here is a complete solution:

The _ctl file:

require File.expand_path(File.dirname(__FILE__)) + '/../../config/boot'
rails_root = File.expand_path RAILS_ROOT
Dir.chdir(rails_root) # Change current directory to RAILS_ROOT
ENV['RAILS_ENV'] ||= "production"
#require "config/environment" # Start up rails
require 'rubygems'
require "daemons"
require 'yaml'
require 'erb'
require 'active_support'

options = YAML.load(ERB.new(IO.read(rails_root + "/config/daemons.yml")).result).with_indifferent_access
options[:dir_mode] = options[:dir_mode].to_sym

Daemons.run rails_root + '/lib/daemons/invites.rb', options

**********************************
The actual daemon file:
#!/usr/bin/env ruby
require File.expand_path(File.dirname(__FILE__)) + '/../../config/boot'
rails_root = File.expand_path RAILS_ROOT

#You might want to change this
ENV["RAILS_ENV"] ||= "production"

Dir.chdir(rails_root) # Change current directory to RAILS_ROOT
require "config/environment" # Start up rails

$running = true;
Signal.trap("TERM") do
$running = false
end

while($running) do

# Replace this with your code
ActiveRecord::Base.logger << "This daemon is still running at #{Time.now}.\n"

sleep 10
end

**********************************
above should work - check you Debug/Production log.

I'm using this approach for invites delivery on TrustedOnes. Let me know if you'd like an invite :-)

Gravatar

justus

September 13 2008 08:45

Thanks for putting this togehter.

I have a problem with stopping the daemon (on the production server).

Usually stopping it with 'ruby script/daemons stop' works fine in any environments. But now there is one instant of the daemon that just keeps running no matter what I do.

Even if I update everything , delete the daemon code, stopped the deamon in all previous releases - all didn't help.

Any suggestions on how I can a.) find that daemon that is still running b.) finally stop it?

Thanks,
Justus

Gravatar

aleco

September 29 2008 21:45

Arman, if your log isn't updating use:

RAILS_DEFAULT_LOGGER.auto_flushing = 1

as the production log will only 'flush' to disk once there's 1000 bytes in memory waiting to be written.

Gravatar

Santosh

February 16 2009 07:38

My question is for Douglas F Shearer.

how can i use daemon-generator on windows platform?

Add Your Comments


(Required)

Your email address to get your Gravatar. Address itself is not shown.

(Include the http://)

(Required)

 

You Are Here


Douglas F Shearer

This is the homepage of Douglas F Shearer, a software developer and mountainbike racer. More…

Hire Me!


I'm available for hire. Ruby, Java and PHP work, both remotely (Worldwide) and locally (Scotland). Find out more or email me.

Flickr Latest


Stay Informed


What is RSS?

Categories


  1. Bike (83)
  2. Coding (82)
  3. Other (45)

Top Tags