source: branches/locker-dev/locker/deploy/bin/rails @ 1408

Last change on this file since 1408 was 1408, checked in by mitchb, 13 years ago
Make Rails autoinstalls pick up code changes automatically Ordinarily, a Rails app in production mode running as an fcgi will continue to use old code, necessitating being killed on all of our servers that have an instance of it hanging around. This patch causes the fcgi to notice application changes and reload itself automatically, providing functionality similar to the enhancement we made for Django in r1278. However, unlike Django, the Rails fcgi is able to reload without needing to be killed with fire in order to avoid fcgi renegotiation issues. This code was developed and contributed by Greg Brockman <gdb@mit.edu>. I've just tested and incorporated it into the scripts autoinstaller.
  • Property svn:executable set to *
File size: 5.3 KB
Line 
1#!/usr/bin/perl
2use strict;
3use FindBin qw($Bin);
4use lib $Bin;
5use onserver;
6use Tie::File;
7
8setup();
9
10sub make_db {
11    my($type) = @_;
12    print "\nCreating $type SQL database for $sname...\n";
13    open GETPWD, '-|', "/mit/scripts/sql/bin$scriptsdev/get-password";
14    ($sqlhost, $sqluser, $sqlpass) = split(/\s/, <GETPWD>);
15    close GETPWD;
16    open SQLDB, '-|', "/mit/scripts/sql/bin$scriptsdev/get-next-database", "${addrlast}_${type}";
17    $sqldb = <SQLDB>;
18    close SQLDB;
19    open SQLDB, '-|', "/mit/scripts/sql/bin$scriptsdev/create-database", $sqldb;
20    $sqldb = <SQLDB>;
21    close SQLDB;
22    if($sqldb eq "") {
23        print "\nERROR:\n";
24        print "Your SQL account failed to create a SQL database.\n";
25        print "You should log in at http://sql.mit.edu to check whether\n";
26        print "your SQL account is at its database limit or its storage limit.\n";
27        print "If you cannot determine the cause of the problem, please\n";
28        print "feel free to contact sql\@mit.edu for assistance.\n";
29        open FAILED, ">.failed";
30        close FAILED;
31        exit 1;
32    }
33    return $sqldb;
34}
35
36my $dev_db = make_db("development");
37my $test_db = make_db("test");
38my $prod_db = make_db("production");
39
40system qw{rails -D -d mysql .};
41
42open PUBLIC_HTACCESS, ">public/.htaccess";
43print PUBLIC_HTACCESS <<EOF;
44# General Apache options
45Options +FollowSymLinks +ExecCGI
46
47# If you don't want Rails to look in certain directories,
48# use the following rewrite rules so that Apache won't rewrite certain requests
49#
50# Example:
51#   RewriteCond %{REQUEST_URI} ^/notrails.*
52#   RewriteRule .* - [L]
53
54# Redirect all requests not available on the filesystem to Rails
55# By default the cgi dispatcher is used which is very slow
56#
57# For better performance replace the dispatcher with the fastcgi one
58#
59# Example:
60#   RewriteRule ^(.*)\$ dispatch.fcgi [QSA,L]
61RewriteEngine On
62
63# If your Rails application is accessed via an Alias directive,
64# then you MUST also set the RewriteBase in this htaccess file.
65#
66# Example:
67#   Alias /myrailsapp /path/to/myrailsapp/public
68#   RewriteBase /myrailsapp
69
70RewriteRule ^\$ index.html [QSA]
71RewriteRule ^([^.]+)\$ \$1.html [QSA]
72RewriteCond %{REQUEST_FILENAME} !-f
73RewriteRule ^(.*)\$ dispatch.fcgi [QSA,L]
74
75# In case Rails experiences terminal errors
76# Instead of displaying this message you can supply a file here which will be rendered instead
77#
78# Example:
79#   ErrorDocument 500 /500.html
80
81RewriteBase /$addrend/public/
82EOF
83
84open HTACCESS, ">.htaccess";
85print HTACCESS <<EOF;
86RewriteEngine On
87RewriteRule ^(.*)\$ public/\$1 [QSA,L]
88RewriteBase /$addrend/
89EOF
90
91tie my @railsenv, 'Tie::File', 'config/environment.rb';
92unshift @railsenv, "# ENV['RAILS_ENV'] ||= 'production'";
93unshift @railsenv, "# Uncomment below to put Rails into production mode";
94unshift @railsenv, "";
95unshift @railsenv, "ENV['RAILS_RELATIVE_URL_ROOT'] = \"/$addrend\"";
96untie @railsenv;
97
98tie my @railsdb, 'Tie::File', 'config/database.yml';
99for (@railsdb) {
100    s/username:.*$/username: $sqluser/;
101    s/password:.*$/password: $sqlpass/;
102    s/host:.*$/host: $sqlhost/;
103    s/database:.*_development.*/database: $dev_db/;
104    s/database:.*_test.*/database: $test_db/;
105    s/database:.*_production.*/database: $prod_db/;
106}
107untie @railsdb;
108
109tie my @railswelcome, 'Tie::File', 'public/index.html';
110for (@railswelcome) {
111    s/Create your database/Sync your database/;
112    s/to create your database\..*/to create tables in your database.<\/p>/;
113}
114untie @railswelcome;
115
116tie my @railsfcgi, 'Tie::File', 'public/dispatch.fcgi';
117for (@railsfcgi) {
118    s/^[^#]*RailsFCGIHandler/## Commented out by scripts.mit.edu autoinstaller\n## RailsFCGIHandler/;
119}
120untie @railsfcgi;
121open RAILSFCGI, ">>public/dispatch.fcgi";
122print RAILSFCGI <<EOF;
123
124## Added by scripts.mit.edu autoinstaller to reload when app code changes
125Thread.abort_on_exception = true
126
127t1 = Thread.new do
128   RailsFCGIHandler.process!
129end
130
131t2 = Thread.new do
132   # List of directories to watch for changes before reload
133   Thread.current[:watched_dirs] = ['app', 'config', 'db', 'lib', 'public']
134   # Sample filter: /(\.rb|\.erb)\$/.  Default filter: watch all files
135   Thread.current[:watched_extensions] = //
136
137   def modified(file)
138     mtime = File.stat(file).mtime
139     Thread.current[:modifications][file] ||= mtime
140     Thread.current[:modifications][file] != mtime
141   end
142
143   # Don't symlink yourself into a loop.  Please.
144   def modified_dir(dir)
145     Dir.new(dir).each do |file|
146       absfile = File.join(dir, file)
147       if FileTest.directory? absfile
148         next if file == '.' or file == '..'
149         return true if modified_dir(absfile)
150       else
151         return true if Thread.current[:watched_extensions] =~ absfile &&
152           modified(absfile)
153       end
154     end
155     false
156   end
157
158   def reload
159     Thread.current[:modifications] = {}
160     RailsFCGIHandler.reload!
161   end
162
163   Thread.current[:modifications] = {}
164   # Wait until the modify time changes, then reload.
165   while true
166     reload if Thread.current[:watched_dirs].inject(false) {|z, dir| z ||
167       modified_dir(File.join(File.dirname(__FILE__), '..', dir))}
168     sleep 1
169   end
170end
171
172t1.join
173t2.join
174## End of scripts.mit.edu autoinstaller additions
175EOF
176
177print "Your application is located in:\n";
178print "  /mit/$USER/web_scripts/$addrend/\n";
179print "To run programs like rake or script/generate, run\n";
180print "  'ssh -k $USER\@scripts' and cd to the above directory.\n\n";
181press_enter;
182
183exit 0;
Note: See TracBrowser for help on using the repository browser.