views:

21

answers:

1

Hello,

I wrote a script that does maintenance tasks for a rails application. The script uses a class that uses models defined in the application. Just an example, let's say application defines model User, and my class (used within the script), sends messages to it, like User.find id.

I am looking for ways to optimize this script, because right now it has to load the application environment: require '../config/environment'. This takes ~15 seconds.

Had the script not use application codebase to do its job, I could have replaced model abstractions with raw SQL. But unfortunatly I can't do that because I would have to repeat the code in the script that is already present in the codebase. Not only would this violate DRY principle and require alot of work, the script would not be very maintainable, in case the model methods that I am using change.

I would like to hear ideas how to approach this problem. The script is not run from the application itself, but from the shell (with Capistrano for instance).

I hope I've described the problem clear enough. Thank you.

A: 

Could you write a little daemon that is in a read on a pipe (or named fifo, or unix domain socket, or, with more complexity, a tcp port) that accepts 'commands' that would be run on your database?

#!/usr/bin/ruby

require '../config/environment'

while (true) do
  File.open("/tmp/fifo", "r") do |f|
    f.each_line do |line|
      case line     
        when "cleanup" then puts "clean!"
        when "publish" then puts "published!"
        else puts "invalid command, ignoring"
      end           
    end     
  end
end

You could start this thing up with vixie cron's @reboot specifier, or you could run it via capistrano commands, or run it out of init or init scripts. Then you write your capistrano rules (that you have now) to simply echo commands into the fifo:

First,

mkfifo /tmp/fifo

In one terminal:

$ ./env.rb

In another terminal:

$ echo -n "cleanup" > /tmp/fifo
$ echo -n "publish" > /tmp/fifo
$ echo -n "go away" > /tmp/fifo

The output in the first terminal looks like this:

clean!
published!
invalid command, ignoring

You could make the matching as friendly (perhaps allow plain echo, rather than require echo -n as my example does) or unfriendly as you want. And the commands that get run can of course call into your model files to do their work.

Please make sure you choose a good location for your fifo -- /tmp/ is probably a bad place, as many distributions clear it on reboot. Also make sure you set the fifo owner and permission (chown and chmod) appropriately for your application -- you might not want to allow your Firefox's flash plugin to write to this file and command your database.

sarnold
Thanks for an incredibly detailed answer, sarnold! Your solutions seems viable, but this task will be added to cronjobs (to keep things unified). This is important because this is just one of many maintenance tasks. But I will definetly try your approach when I have a chance. Right now it seems there ain't a solution that fits my needs, so I'll have to live with 15 second initialization. Again, many thanks for your time!
JobGovernor
Your cronjob could just as easily be specified: 0 * * * * /bin/echo -n "cleanup" > /var/run/JobSocket
sarnold