Housekeeping

There are a few techniques that are rarely covered in the Rails printed literature, even though they are essential to keeping Rails applications in good working order. This section covers these bits and pieces.

Starting Mongrel Automatically

Currently, Mongrel has to be started and stopped manually from the development machine. If the production server is rebooted, someone will have to remember to restart the application too. A better solution is to add a start/stop script to the production server to run Mongrel automatically with the server.

First, create a *nix script to control the application in script/mongrel_init. Here's an example for Ubuntu:

#!/bin/bash
# Ubuntu Linux init script for Rails application
# set these variables to your production environment
APP_USER=captain
APP_NAME=Intranet
APP_PORT=4000
APP_HOME=/home/captain/apps/Intranet
# more variables - you don't need to set these
CURRENT=$APP_HOME/current
PID=$APP_HOME/shared/pids/mongrel.pid
MONGREL="sudo -u $APP_USER /usr/bin/mongrel_rails"
ENVIRONMENT=production
# load library functions
. /lib/lsb/init-functions
case "$1" in
start)
log_begin_msg "Starting Rails application $APP_NAME"
$MONGREL start -c $CURRENT -e $ENVIRONMENT -p $APP_PORT -P $PID -d
log_end_msg 0
;;
stop)
log_begin_msg "Stopping Rails application $APP_NAME"
$MONGREL stop -P $PID
log_end_msg 0
;;
restart)
log_begin_msg "Restarting Rails application $APP_NAME"
$MONGREL restart -P $PID
log_end_msg 0
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac
exit 0

You'll need to set the variables prefixed with APP_ in the above script to values appropriate to your production server.

Note

This script is in a format that can be used by the *nix initialization (init) system to control Mongrel during server starts, stops, and reboots. For more about *nix init scripts, see http://www.linux.com/article.pl?sid=06/01/03/1728227.

Next, make the script executable:

$ chmod +x script/mongrel_init

This script can now be executed with a start, stop, or restart option, e.g.

$ ./mongrel_init start
$ ./mongrel_init stop
$ ./mongrel_init restart

Deploy the application to the server. Then, on the production server, copy the script from script/mongrel_init into the /etc/init.d directory:

$ sudo cp script/mongrel_init /etc/init.d/mongrel_intranet

Finally, you need to add the script to the initialization sequence for the production server. On Ubuntu Linux, you can do this with:

$ sudo update-rc.d mongrel_intranet defaults

Now Mongrel should start and stop with the server.

Clearing Out Stale Sessions

One other common task you need to perform is clearing out stale session files (i.e. sessions associated with clients who are no longer connecting to the application). Rails doesn't do this automatically for you. If you are using file system sessions (see the section Cookies and Sessions in Rails in Chapter 8) and have a busy site, the RAILS_ROOT/tmp/sessions directory for your application can rapidly fill up with session files as a result.

Rails provides a simple Rake task to clear out stale session files:

$ rake tmp:sessions:clear

This script just does a blanket clean-up of session files, regardless of whether they are still in use. However, it's simple enough to write a script that will clear out any session files in a time-sensitive fashion, which should leave behind those still being actively used. For example, here's one to clear sessions that were last accessed more than 6 hours ago, which you can add to script/clear_sessions:

#!/bin/bash
# Clear out stale sessions (last accessed more than 6 hours ago)
/usr/bin/find /home/captain/apps/Intranet/current/tmp/sessions 
-name "ruby_sess*" -amin +360 -exec rm {} ;

The session files for the application are all prefixed with"ruby_sess". This script finds all of the files in the sessions directory (RAILS_ROOT/tmp/sessions), matching this file name pattern (the -name switch) that were last accessed (the -amin switch) more than 6 hours (360 minutes) ago (+360). Each matching file is passed to the rm command (via the -exec switch), which removes it.

Make the script executable:

$ chmod +x script/clear_sessions

Deploy the script to the production server. Make sure it is still executable once deployed.

To call the script on a schedule, set up a cron job to run every hour on the production server, using whatever cron tools you have available. You should do this as the captain user, who has permission to write into the sessions directory. For example:

$ su - captain
Password:
$ crontab -e

will open up captain's crontab for editing. Add this line:

0 * * * * /home/captain/apps/Intranet/current/script/clear_sessions

which schedules the clear_sessions.sh script to run at 0 minutes past every hour of every day. If things are working correctly, you should see entries like this in /var/log/syslog, indicating that the command ran:

May 9 00:00:41 demo-server /USR/SBIN/CRON[7079]: (captain) CMD (/home/captain/apps/Intranet/current/script/clear_sessions)

If the script fails to run correctly, you'll get error messages sent to the standard Linux mail spool; for the captain user on Ubuntu, this goes to /var/mail/captain. An individual error email looks something like this:

From captain@demo-server Wed May 09 00:00:41 2007
...
From: root@demo-server (Cron Daemon)
To: captain@demo-server
Subject: Cron <captain@demo-server> /home/captain/apps/Intranet/current/script/clear_sessions
...
Date: Wed, 09 May 2007 00:00:41 +0100
/bin/sh: /home/captain/apps/Intranet/current/script/clear_sessions: Permission denied

Emailed errors can be useful in helping track down problems with a cron job. If you have an email server correctly configured for email, you could forward the output from cron jobs to an arbitrary administrator email address instead.

Keeping Log Files Manageable

The Rails log files are essential for tracking down issues with your application. However, after a few weeks or months of operation, those files start to get big. As well as taking up disk space, this can make them slow to open with a text editor for viewing.

The solution is to rotate the logs; that is, periodically rename the current log, and archive it, and open a fresh empty file for storing new log entries. Here's a sample Ruby script for doing this, which you could place in script/rotate_logs:

#!/usr/bin/env ruby
# Rotate logs on production server; call via cron
LOG_ROOT = File.join(File.dirname(__FILE__), '../log')
suffix = Time.now.strftime('%Y-%m-%d')
['mongrel', 'production'].each do |log_for|
log_file = File.join(LOG_ROOT, log_for + '.log')
archived_log_file = log_file + '.' + suffix
File.rename(log_file, archived_log_file)
File.new(log_file, 'w')
end

This script takes the current mongrel.log and production.log script and renames them, appending the date in YYYY-MM-DD format to each filename as a new suffix. It then creates new empty log files, mongrel.log and production.log, which the application can continue logging into. Make sure you deploy the new script to the server (using cap deploy).

To run the script periodically, add it to the captain user's crontab (see the previous section for instructions on editing crontab). For example, adding this line to the crontab will run the script at seven minutes past midnight every day:

7 0 * * * /usr/bin/ruby  /home/captain/apps/Intranet/current/script/rotate_logs

A final nicety is to ensure that all the custom scripts we're adding are made executable when deployed to the production server. (I found myself doing this manually each time I deployed new scripts, as the correct permissions weren't being stored in the Subversion repository.) You can do this by adding a new Capistrano task to config/deploy.rb called make_scripts_executable, and then by including this script as part of the after_update_code task (see the earlier section Centralizing File Uploads):

desc "Make all custom scripts (in script directory) executable"
task :make_scripts_executable, :roles => :app do
run "chmod -R u+x #{release_path}/script"
end
task :after_update_code do
symlink_for_file_uploads
make_scripts_executable

end

Note that you could go even further than this, and add a handler to cold_deploy to create the cron jobs for you. That task is left as an exercise for you.

Reducing Log Detail

One other way of managing logs more effectively is to reduce the amount of detail they contain. Rails supports different so-called log levels. The best way to imagine these is as representing different levels of sensitivity; the lower the log level, the less sensitive the logging system is; the less sensitive it is, the less it reports on what the application is doing. The log levels available are:

  • :debug (most sensitive)
  • :info
  • :warn
  • :error
  • :fatal (least sensitive)

The log level can be configured as per environment. The default log levels for each environment are as follows:

  • test: log level = :debug
  • development: log level = :debug
  • production: log level = :info

I'd recommend leaving the log levels for test and development as they are, at their most sensitive. However, for production, you may find that you don't want such verbose logging (the :info log level includes details of every controller/action invocation, templates rendered, time for rendering etc., which can result in large log files very quickly).

To reduce the sensitivity of logging, edit config/environments/production.rb and set the config.log_level directive as follows:

config.log_level = :error

Note

You'll need to restart Mongrel for the new log level to take effect.

Setting the log level to :error tells Rails to ignore warnings and only report on errors (serious and fatal). In turn, this reduces the amount of data written into the logs, which means they don't grow so rapidly. If you find that reducing logging in this way makes it hard for you to track down errors when they occur, you can always turn up the sensitivity again.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.173.53