mongrel 0.3.6 → 0.3.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README +28 -1
- data/Rakefile +2 -2
- data/bin/mongrel_rails +102 -65
- data/bin/mongrel_rails_service +16 -7
- data/bin/mongrel_rails_svc +184 -87
- data/doc/rdoc/classes/Mongrel.html +1 -0
- data/doc/rdoc/classes/Mongrel/Const.html +3 -3
- data/doc/rdoc/classes/Mongrel/HeaderOut.html +10 -10
- data/doc/rdoc/classes/Mongrel/HeaderOut.src/{M000028.html → M000014.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HeaderOut.src/{M000029.html → M000015.html} +7 -7
- data/doc/rdoc/classes/Mongrel/HttpParser.html +35 -35
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000015.html → M000001.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000016.html → M000002.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000017.html → M000003.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000018.html → M000004.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000019.html → M000005.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000020.html → M000006.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000021.html → M000007.html} +0 -0
- data/doc/rdoc/classes/Mongrel/HttpRequest.html +5 -5
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/{M000041.html → M000029.html} +25 -25
- data/doc/rdoc/classes/Mongrel/HttpResponse.html +36 -36
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000034.html → M000016.html} +7 -7
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000035.html → M000017.html} +6 -6
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000036.html → M000018.html} +5 -5
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000037.html → M000019.html} +5 -5
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000038.html → M000020.html} +6 -6
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000039.html → M000021.html} +6 -6
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000040.html → M000022.html} +6 -6
- data/doc/rdoc/classes/Mongrel/HttpServer.html +34 -35
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000008.html +36 -0
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000023.html → M000009.html} +43 -43
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000024.html → M000010.html} +31 -31
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000025.html → M000011.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000026.html → M000012.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000013.html +23 -0
- data/doc/rdoc/classes/{FactoryError.html → Mongrel/TimeoutWorker.html} +7 -34
- data/doc/rdoc/classes/Mongrel/URIClassifier.html +63 -20
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000023.html +18 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000024.html +18 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000030.html → M000025.html} +0 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000031.html → M000026.html} +0 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000032.html → M000027.html} +0 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000033.html → M000028.html} +0 -0
- data/doc/rdoc/created.rid +1 -1
- data/doc/rdoc/files/README.html +35 -2
- data/doc/rdoc/files/lib/mongrel_rb.html +4 -1
- data/doc/rdoc/fr_class_index.html +1 -2
- data/doc/rdoc/fr_file_index.html +0 -1
- data/doc/rdoc/fr_method_index.html +29 -41
- data/lib/mongrel.rb +37 -9
- data/lib/mongrel/command.rb +13 -34
- data/lib/mongrel/plugins.rb +156 -0
- data/lib/mongrel/rails.rb +70 -0
- data/test/plugins/commands/test1.rb +19 -0
- data/test/test_plugins.rb +45 -0
- data/test/test_uriclassifier.rb +5 -1
- metadata +38 -49
- data/doc/rdoc/classes/FactoryError.src/M000001.html +0 -23
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000022.html +0 -33
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000027.html +0 -19
- data/doc/rdoc/classes/PluginFactory.html +0 -409
- data/doc/rdoc/classes/PluginFactory.src/M000002.html +0 -18
- data/doc/rdoc/classes/PluginFactory.src/M000003.html +0 -18
- data/doc/rdoc/classes/PluginFactory.src/M000004.html +0 -22
- data/doc/rdoc/classes/PluginFactory.src/M000005.html +0 -22
- data/doc/rdoc/classes/PluginFactory.src/M000006.html +0 -33
- data/doc/rdoc/classes/PluginFactory.src/M000007.html +0 -32
- data/doc/rdoc/classes/PluginFactory.src/M000008.html +0 -18
- data/doc/rdoc/classes/PluginFactory.src/M000009.html +0 -24
- data/doc/rdoc/classes/PluginFactory.src/M000010.html +0 -40
- data/doc/rdoc/classes/PluginFactory.src/M000011.html +0 -39
- data/doc/rdoc/classes/PluginFactory.src/M000012.html +0 -24
- data/doc/rdoc/classes/PluginFactory.src/M000013.html +0 -70
- data/doc/rdoc/classes/PluginFactory.src/M000014.html +0 -34
- data/doc/rdoc/files/lib/pluginfactory_rb.html +0 -132
- data/lib/pluginfactory.rb +0 -384
data/README
CHANGED
@@ -14,7 +14,8 @@ scream without too many portability issues.
|
|
14
14
|
The 0.3.6 release supports Ruby On Rails much better than previously, and also
|
15
15
|
sports the beginning of a command and plugin infrastructure. There is now a more
|
16
16
|
complete CGIWrapper that handles most of the CGI usage, but still doesn't do the
|
17
|
-
MIME decoding or file upload/send (it leaves that to CGI).
|
17
|
+
MIME decoding or file upload/send (it leaves that to CGI). Finally, there's a
|
18
|
+
great mongrel_rails_service script for running under Win32 as a service.
|
18
19
|
|
19
20
|
After you've installed (either with gem install mongrel or via source) you should
|
20
21
|
have the mongrel_rails command available in your PATH. Then you just do the following:
|
@@ -42,6 +43,32 @@ There are also many more new options for configuring the rails runner including
|
|
42
43
|
changing to a different directory, adding more MIME types, and setting processor
|
43
44
|
threads and timeouts.
|
44
45
|
|
46
|
+
|
47
|
+
=== Win32 Service Support
|
48
|
+
|
49
|
+
Mongrel now has support for running as a Win32 service right out of the
|
50
|
+
box. The support is still rough but works well enough that we decided
|
51
|
+
to release it. You can thank Luis Lavena for working on this and making
|
52
|
+
it so nice.
|
53
|
+
|
54
|
+
After you do the gem install, find a Rails application you want to run
|
55
|
+
and do:
|
56
|
+
|
57
|
+
$ mongrel_rails_service install -n myapp \
|
58
|
+
-r c:\my\path\to\myapp -p 4000 -e production
|
59
|
+
$ mongrel_rails_service start -n myapp
|
60
|
+
|
61
|
+
Now hit the port and poof, works. *Stopping the service is a little problematic right now.*
|
62
|
+
|
63
|
+
If you run into an app that's not running right, my suggestion is to run it with
|
64
|
+
the regular mongrel_rails runner:
|
65
|
+
|
66
|
+
$ cd c:\my\path\to\myapp
|
67
|
+
$ mongrel_rails start -p 4500
|
68
|
+
|
69
|
+
Since that will spit out error messages and stuff to the console. *Use CTRL-Pause/Break to stop.*
|
70
|
+
|
71
|
+
|
45
72
|
== Install
|
46
73
|
|
47
74
|
It doesn't explicitly require Camping, but if you want to run the examples/camping/
|
data/Rakefile
CHANGED
@@ -30,7 +30,7 @@ end
|
|
30
30
|
|
31
31
|
setup_extension("http11", "http11")
|
32
32
|
|
33
|
-
version="0.3.
|
33
|
+
version="0.3.7"
|
34
34
|
summary = "A small fast HTTP library and server that runs Rails, Camping, and Nitro apps."
|
35
35
|
test_file = "test/test_ws.rb"
|
36
36
|
author="Zed A. Shaw"
|
@@ -44,7 +44,7 @@ end
|
|
44
44
|
desc "Build a binary gem for Win32"
|
45
45
|
task :win32_gem => [:clean, :compile, :test, :rerdoc, :package_win32]
|
46
46
|
|
47
|
-
scripts_win32 = scripts + ['mongrel_rails_service'
|
47
|
+
scripts_win32 = scripts + ['mongrel_rails_service']
|
48
48
|
task :package_win32 do
|
49
49
|
setup_win32_gem(name, version, version, summary, scripts_win32, test_file) do |spec|
|
50
50
|
spec.add_dependency('win32-service', '>= 0.5.0')
|
data/bin/mongrel_rails
CHANGED
@@ -1,61 +1,24 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'mongrel'
|
3
|
-
require 'mongrel/command'
|
2
|
+
require 'mongrel/rails'
|
4
3
|
|
5
4
|
|
6
|
-
class
|
7
|
-
|
8
|
-
def initialize(dir, mime_map = {})
|
9
|
-
@files = Mongrel::DirHandler.new(dir,false)
|
10
|
-
@guard = Mutex.new
|
11
|
-
|
12
|
-
# register the requested mime types
|
13
|
-
mime_map.each {|k,v| Mongrel::DirHandler::add_mime_type(k,v) }
|
14
|
-
end
|
15
|
-
|
16
|
-
def process(request, response)
|
17
|
-
# not static, need to talk to rails
|
18
|
-
return if response.socket.closed?
|
19
|
-
|
20
|
-
if @files.can_serve(request.params["PATH_INFO"])
|
21
|
-
@files.process(request,response)
|
22
|
-
else
|
23
|
-
cgi = Mongrel::CGIWrapper.new(request, response)
|
24
|
-
|
25
|
-
begin
|
26
|
-
@guard.synchronize do
|
27
|
-
# Rails is not thread safe so must be run entirely within synchronize
|
28
|
-
Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, response.body)
|
29
|
-
end
|
30
|
-
|
31
|
-
# This finalizes the output using the proper HttpResponse way
|
32
|
-
cgi.out {""}
|
33
|
-
rescue Object => rails_error
|
34
|
-
STDERR.puts "calling Dispatcher.dispatch #{rails_error}"
|
35
|
-
STDERR.puts rails_error.backtrace.join("\n")
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
class StartCommand < Mongrel::Command::Command
|
5
|
+
class Start < Mongrel::Plugin "/commands"
|
6
|
+
include Mongrel::Command::Base
|
45
7
|
|
46
8
|
def configure
|
47
9
|
options [
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
10
|
+
["-e", "--environment ENV", "Rails environment to run as", :@environment, ENV['RAILS_ENV'] || "development"],
|
11
|
+
["-d", "--daemonize", "Whether to run in the background or not", :@daemon, false],
|
12
|
+
['-p', '--port PORT', "Which port to bind to", :@port, 3000],
|
13
|
+
['-a', '--address ADDR', "Address to bind to", :@address, "0.0.0.0"],
|
14
|
+
['-l', '--log FILE', "Where to write log messages", :@log_file, "log/mongrel.log"],
|
15
|
+
['-P', '--pid FILE', "Where to write the PID", :@pid_file, "log/mongrel.pid"],
|
16
|
+
['-n', '--num-procs INT', "Number of processor threads to use", :@num_procs, 20],
|
17
|
+
['-t', '--timeout SECONDS', "Timeout all requests after SECONDS time", :@timeout, 120],
|
18
|
+
['-m', '--mime PATH', "A YAML file that lists additional MIME types", :@mime_map, nil],
|
19
|
+
['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, Dir.pwd],
|
20
|
+
['-r', '--root PATH', "Set the document root (default 'public')", :@docroot, "public"],
|
21
|
+
['-L', '--load PATH', "Loads plugins from the given directory", :@load_from, nil],
|
59
22
|
]
|
60
23
|
end
|
61
24
|
|
@@ -71,9 +34,12 @@ class StartCommand < Mongrel::Command::Command
|
|
71
34
|
valid_dir? @docroot, "Path to docroot not valid: #@docroot"
|
72
35
|
valid_exists? @mime_map, "MIME mapping file does not exist: #@mime_map" if @mime_map
|
73
36
|
|
37
|
+
valid_dir? @load_from, "Plugin directory path does not exist" if @load_from
|
38
|
+
|
74
39
|
return @valid
|
75
40
|
end
|
76
41
|
|
42
|
+
|
77
43
|
def daemonize
|
78
44
|
# save this for later since daemonize will hose it
|
79
45
|
if @daemon and RUBY_PLATFORM !~ /mswin/
|
@@ -117,22 +83,47 @@ class StartCommand < Mongrel::Command::Command
|
|
117
83
|
end
|
118
84
|
|
119
85
|
def start_mongrel(rails)
|
120
|
-
|
86
|
+
@restart = false
|
87
|
+
|
121
88
|
server = Mongrel::HttpServer.new(@address, @port, @num_procs.to_i, @timeout.to_i)
|
122
89
|
server.register("/", rails)
|
123
90
|
server.run
|
124
|
-
|
91
|
+
|
92
|
+
# signal trapping just applies to posix systems
|
93
|
+
# TERM is a valid signal, but still doesn't gracefuly shutdown on win32.
|
94
|
+
if RUBY_PLATFORM !~ /mswin/
|
95
|
+
# graceful shutdown
|
96
|
+
trap("TERM") {
|
97
|
+
server.stop
|
98
|
+
}
|
99
|
+
|
100
|
+
# rails reload
|
101
|
+
trap("HUP") {
|
102
|
+
server.stop
|
103
|
+
@restart = true
|
104
|
+
}
|
105
|
+
|
106
|
+
# restart
|
107
|
+
trap("USR2") {
|
108
|
+
server.stop
|
109
|
+
@restart = true
|
110
|
+
}
|
111
|
+
end
|
125
112
|
|
126
113
|
begin
|
127
|
-
puts "Server ready."
|
114
|
+
STDERR.puts "Server ready."
|
128
115
|
server.acceptor.join
|
129
116
|
rescue Interrupt
|
130
|
-
puts "Interrupted."
|
117
|
+
STDERR.puts "Interrupted."
|
131
118
|
raise
|
132
119
|
end
|
120
|
+
|
121
|
+
# daemonize makes restart easy
|
122
|
+
run if @restart
|
133
123
|
end
|
134
124
|
|
135
125
|
def run
|
126
|
+
Mongrel::PluginManager.instance.load(@load_from) if @load_from
|
136
127
|
daemonize
|
137
128
|
rails = configure_rails
|
138
129
|
start_mongrel(rails)
|
@@ -140,12 +131,26 @@ class StartCommand < Mongrel::Command::Command
|
|
140
131
|
end
|
141
132
|
|
142
133
|
|
134
|
+
def send_signal(signal, pid_file)
|
135
|
+
pid = open(pid_file).read.to_i
|
136
|
+
print "Sending #{signal} to Mongrel at PID #{pid}..."
|
137
|
+
begin
|
138
|
+
Process.kill(signal, pid)
|
139
|
+
rescue Errno::ESRCH
|
140
|
+
puts "Process does not exist. Not running."
|
141
|
+
end
|
142
|
+
|
143
|
+
puts "Done."
|
144
|
+
end
|
145
|
+
|
143
146
|
|
144
|
-
class
|
147
|
+
class Stop < Mongrel::Plugin "/commands"
|
148
|
+
include Mongrel::Command::Base
|
145
149
|
|
146
150
|
def configure
|
147
|
-
options [
|
151
|
+
options [
|
148
152
|
['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, Dir.pwd],
|
153
|
+
['-f', '--force', "Force the shutdown.", :@force, false],
|
149
154
|
['-P', '--pid FILE', "Where to write the PID", :@pid_file, "log/mongrel.pid"]
|
150
155
|
]
|
151
156
|
end
|
@@ -162,16 +167,48 @@ class StopCommand < Mongrel::Command::Command
|
|
162
167
|
|
163
168
|
|
164
169
|
def run
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
170
|
+
if @force
|
171
|
+
send_signal("KILL", @pid_file)
|
172
|
+
else
|
173
|
+
send_signal("TERM", @pid_file)
|
174
|
+
end
|
175
|
+
|
176
|
+
File.unlink(@pid_file)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
|
182
|
+
class Restart < Mongrel::Plugin "/commands"
|
183
|
+
include Mongrel::Command::Base
|
184
|
+
|
185
|
+
def configure
|
186
|
+
options [
|
187
|
+
['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, Dir.pwd],
|
188
|
+
['-s', '--soft', "Do a soft restart rather than a process exit restart", :@soft, false],
|
189
|
+
['-P', '--pid FILE', "Where to write the PID", :@pid_file, "log/mongrel.pid"]
|
190
|
+
]
|
191
|
+
end
|
192
|
+
|
193
|
+
def validate
|
194
|
+
@cwd = File.expand_path(@cwd)
|
195
|
+
valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd"
|
196
|
+
|
197
|
+
@pid_file = File.join(@cwd,@pid_file)
|
198
|
+
valid_exists? @pid_file, "PID file #@pid_file does not exist. Not running?"
|
199
|
+
|
200
|
+
return @valid
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
def run
|
205
|
+
if @soft
|
206
|
+
send_signal("HUP", @pid_file)
|
207
|
+
else
|
208
|
+
send_signal("USR2", @pid_file)
|
171
209
|
end
|
172
210
|
|
173
211
|
File.unlink(@pid_file)
|
174
|
-
puts "Done."
|
175
212
|
end
|
176
213
|
end
|
177
214
|
|
data/bin/mongrel_rails_service
CHANGED
@@ -7,8 +7,6 @@
|
|
7
7
|
###############################################
|
8
8
|
require 'rubygems'
|
9
9
|
require 'mongrel'
|
10
|
-
require 'mongrel/command'
|
11
|
-
|
12
10
|
require 'win32/service'
|
13
11
|
include Win32
|
14
12
|
|
@@ -32,7 +30,8 @@ module GenericCommand
|
|
32
30
|
end
|
33
31
|
end
|
34
32
|
|
35
|
-
class
|
33
|
+
class Install < Mongrel::Plugin "/commands"
|
34
|
+
include Mongrel::Command::Base
|
36
35
|
|
37
36
|
# Default every option to nil so only the defined ones get passed to service
|
38
37
|
# (which will override ServiceCommand defaults).
|
@@ -41,12 +40,13 @@ class InstallCommand < Mongrel::Command::Command
|
|
41
40
|
['-n', '--name SVC_NAME', "Required name for the service to be registered/installed.", :@svc_name, nil],
|
42
41
|
['-d', '--display SVC_DISPLAY', "Adjust the display name of the service.", :@svc_display, nil],
|
43
42
|
['-r', '--root PATH', "Set the root path where your rails app resides.", :@rails_root, Dir.pwd],
|
44
|
-
['-e', '--environment ENV', "Rails environment to run as", :@environment, 'production'],
|
43
|
+
['-e', '--environment ENV', "Rails environment to run as. (default: production)", :@environment, 'production'],
|
45
44
|
['-b', '--binding ADDR', "Address to bind to", :@ip, nil],
|
46
45
|
['-p', '--port PORT', "Which port to bind to", :@port, 3000],
|
47
46
|
['-m', '--mime PATH', "A YAML file that lists additional MIME types", :@mime_map, nil],
|
48
47
|
['-P', '--num-procs INT', "Number of processor threads to use", :@num_procs, nil],
|
49
48
|
['-t', '--timeout SECONDS', "Timeout all requests after SECONDS time", :@timeout, nil],
|
49
|
+
['-c', '--cpu CPU', "Bind the process to specific cpu, starting from 1.", :@cpu, nil]
|
50
50
|
]
|
51
51
|
end
|
52
52
|
|
@@ -70,6 +70,9 @@ class InstallCommand < Mongrel::Command::Command
|
|
70
70
|
valid? app_exist == true, "The root of rails app isn't valid, please verify."
|
71
71
|
valid_exists? @mime_map, "MIME mapping file does not exist: #@mime_map" if @mime_map
|
72
72
|
|
73
|
+
# Validate the number of cpu to bind to.
|
74
|
+
valid? @cpu.to_i > 0, "You must specify a numeric value for cpu. (1..8)" if @cpu
|
75
|
+
|
73
76
|
# We should validate service existance here, right Zed?
|
74
77
|
begin
|
75
78
|
valid? !Service.exists?(@svc_name), "The service already exist, please uninstall it first."
|
@@ -112,6 +115,9 @@ class InstallCommand < Mongrel::Command::Command
|
|
112
115
|
|
113
116
|
# timeout
|
114
117
|
@params << "-t #{@timeout.to_i} " if @timeout
|
118
|
+
|
119
|
+
# cpu
|
120
|
+
@params << "-c #{@cpu.to_i} " if @cpu
|
115
121
|
end
|
116
122
|
|
117
123
|
def install_service
|
@@ -168,7 +174,8 @@ class InstallCommand < Mongrel::Command::Command
|
|
168
174
|
end
|
169
175
|
end
|
170
176
|
|
171
|
-
class
|
177
|
+
class Delete < Mongrel::Plugin "/commands"
|
178
|
+
include Mongrel::Command::Base
|
172
179
|
include GenericCommand
|
173
180
|
|
174
181
|
def run
|
@@ -186,7 +193,8 @@ class DeleteCommand < Mongrel::Command::Command
|
|
186
193
|
end
|
187
194
|
end
|
188
195
|
|
189
|
-
class
|
196
|
+
class Start < Mongrel::Plugin "/commands"
|
197
|
+
include Mongrel::Command::Base
|
190
198
|
include GenericCommand
|
191
199
|
|
192
200
|
def run
|
@@ -210,7 +218,8 @@ class StartCommand < Mongrel::Command::Command
|
|
210
218
|
end
|
211
219
|
end
|
212
220
|
|
213
|
-
class
|
221
|
+
class Stop < Mongrel::Plugin "/commands"
|
222
|
+
include Mongrel::Command::Base
|
214
223
|
include GenericCommand
|
215
224
|
|
216
225
|
def run
|
data/bin/mongrel_rails_svc
CHANGED
@@ -4,75 +4,57 @@
|
|
4
4
|
# This is where Win32::Daemon resides.
|
5
5
|
###############################################
|
6
6
|
require 'rubygems'
|
7
|
-
require 'mongrel'
|
8
|
-
|
7
|
+
require 'mongrel/rails'
|
9
8
|
require 'optparse'
|
10
|
-
|
11
9
|
require 'win32/service'
|
12
10
|
|
13
|
-
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
@guard = Mutex.new
|
25
|
-
|
26
|
-
# register the requested mime types
|
27
|
-
mime_map.each {|k,v| Mongrel::DirHandler::add_mime_type(k,v) }
|
11
|
+
# We need to use OpenProcess and SetProcessAffinityMask on WinNT/2K/XP for
|
12
|
+
# binding the process to each cpu.
|
13
|
+
# Kernel32 Module Just for Win32 :D
|
14
|
+
require 'dl/win32'
|
15
|
+
|
16
|
+
module Kernel32
|
17
|
+
[
|
18
|
+
%w/OpenProcess LLL L/,
|
19
|
+
%w/SetProcessAffinityMask LL L/,
|
20
|
+
].each do |fn|
|
21
|
+
const_set fn[0].intern, Win32API.new('kernel32.dll', *fn)
|
28
22
|
end
|
29
23
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
if @files.can_serve(request.params["PATH_INFO"])
|
35
|
-
@files.process(request,response)
|
36
|
-
else
|
37
|
-
cgi = Mongrel::CGIWrapper.new(request, response)
|
38
|
-
|
39
|
-
begin
|
40
|
-
@guard.synchronize do
|
41
|
-
# Rails is not thread safe so must be run entirely within synchronize
|
42
|
-
Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, response.body)
|
43
|
-
end
|
44
|
-
|
45
|
-
# This finalizes the output using the proper HttpResponse way
|
46
|
-
cgi.out {""}
|
47
|
-
rescue Object => rails_error
|
48
|
-
STDERR.puts "calling Dispatcher.dispatch #{rails_error}"
|
49
|
-
STDERR.puts rails_error.backtrace.join("\n")
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
24
|
+
PROCESS_ALL_ACCESS = 0x1f0fff
|
25
|
+
|
26
|
+
module_function
|
53
27
|
|
28
|
+
def set_affinity(pid, cpu)
|
29
|
+
handle = OpenProcess.call(PROCESS_ALL_ACCESS, 0, pid)
|
30
|
+
|
31
|
+
# CPU mask is a bit weird, hehehe :)
|
32
|
+
# default mask for CPU 1
|
33
|
+
mask = 1
|
34
|
+
mask = %w{1 2 4 8 16 32 64 128}[cpu.to_i - 1] if cpu.to_i.between?(1, 8)
|
35
|
+
|
36
|
+
SetProcessAffinityMask.call(handle, mask.to_i)
|
37
|
+
end
|
54
38
|
end
|
39
|
+
# End Kernel32 Module
|
55
40
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
else
|
66
|
-
# no gzip supported, send it back normal
|
67
|
-
out << results
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
41
|
+
DEBUG_LOG_FILE = File.expand_path(File.dirname(__FILE__) + '/debug.log')
|
42
|
+
DEBUG_THREAD_LOG_FILE = File.expand_path(File.dirname(__FILE__) + '/debug_thread.log')
|
43
|
+
|
44
|
+
def dbg(msg)
|
45
|
+
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - #{msg}") }
|
46
|
+
end
|
47
|
+
|
48
|
+
def dbg_th(msg)
|
49
|
+
File.open(DEBUG_THREAD_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - #{msg}") }
|
71
50
|
end
|
72
51
|
|
73
|
-
class
|
52
|
+
# This class encapsulate the handler registering, http_server and working thread
|
53
|
+
# Is standalone, so using MongrelRails in your app get everything runnig
|
54
|
+
# (in case you don't want use mongrel_rails script)
|
55
|
+
class MongrelRails
|
74
56
|
def initialize(ip, port, rails_root, docroot, environment, mime_map, num_procs, timeout)
|
75
|
-
|
57
|
+
dbg "mongrelrails_initialize entered"
|
76
58
|
|
77
59
|
@ip = ip
|
78
60
|
@port = port
|
@@ -83,11 +65,23 @@ class RailsDaemon < Win32::Daemon
|
|
83
65
|
@num_procs = num_procs
|
84
66
|
@timeout = timeout
|
85
67
|
|
86
|
-
|
68
|
+
dbg "mongrelrails_initialize left"
|
87
69
|
end
|
70
|
+
|
71
|
+
def delayed_initialize
|
72
|
+
dbg "delayed_initialize entered"
|
73
|
+
|
74
|
+
@rails = configure_rails
|
75
|
+
|
76
|
+
# start up mongrel with the right configurations
|
77
|
+
@server = Mongrel::HttpServer.new(@ip, @port, @num_procs.to_i, @timeout.to_i)
|
78
|
+
@server.register("/", @rails)
|
88
79
|
|
80
|
+
dbg "delayed_initialize left"
|
81
|
+
end
|
82
|
+
|
89
83
|
def load_mime_map
|
90
|
-
|
84
|
+
dbg "load_mime_map entered"
|
91
85
|
|
92
86
|
mime = {}
|
93
87
|
|
@@ -100,13 +94,13 @@ class RailsDaemon < Win32::Daemon
|
|
100
94
|
mime.each {|k,v| puts "WARNING: MIME type #{k} must start with '.'" if k.index(".") != 0 }
|
101
95
|
end
|
102
96
|
|
103
|
-
|
97
|
+
dbg "load_mime_map left"
|
104
98
|
|
105
99
|
return mime
|
106
100
|
end
|
107
101
|
|
108
102
|
def configure_rails
|
109
|
-
|
103
|
+
dbg "configure_rails entered"
|
110
104
|
|
111
105
|
Dir.chdir(@rails_root)
|
112
106
|
|
@@ -116,45 +110,85 @@ class RailsDaemon < Win32::Daemon
|
|
116
110
|
# configure the rails handler
|
117
111
|
rails = RailsHandler.new(@docroot, load_mime_map)
|
118
112
|
|
119
|
-
|
113
|
+
dbg "configure_rails left"
|
120
114
|
|
121
115
|
return rails
|
122
116
|
end
|
123
117
|
|
124
|
-
def
|
125
|
-
|
118
|
+
def start_serve
|
119
|
+
dbg "start_serve entered"
|
126
120
|
|
127
|
-
@
|
128
|
-
|
121
|
+
@runner = Thread.new do
|
122
|
+
dbg_th "runner_thread suspended"
|
123
|
+
Thread.stop
|
124
|
+
|
125
|
+
dbg_th "runner_thread resumed"
|
126
|
+
dbg_th "runner_thread acceptor.join"
|
127
|
+
@server.acceptor.join
|
128
|
+
end
|
129
|
+
|
130
|
+
dbg "server.run"
|
131
|
+
@server.run
|
132
|
+
|
133
|
+
dbg "runner.run"
|
134
|
+
@runner.run
|
129
135
|
|
130
|
-
|
131
|
-
|
132
|
-
|
136
|
+
dbg "start_serve left"
|
137
|
+
end
|
138
|
+
|
139
|
+
def stop_serve
|
140
|
+
dbg "stop_serve entered"
|
141
|
+
|
142
|
+
if @runner.alive?
|
143
|
+
dbg "killing thread"
|
144
|
+
@runner.kill
|
145
|
+
end
|
133
146
|
|
134
|
-
|
147
|
+
@server.stop
|
148
|
+
|
149
|
+
dbg "stop_serve left"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
class RailsDaemon < Win32::Daemon
|
154
|
+
def initialize(rails)
|
155
|
+
dbg "daemon_initialize entered"
|
156
|
+
|
157
|
+
@rails = rails
|
158
|
+
|
159
|
+
dbg "daemon_initialize left"
|
160
|
+
end
|
161
|
+
|
162
|
+
def service_init
|
163
|
+
dbg "service_init entered"
|
164
|
+
|
165
|
+
@rails.delayed_initialize
|
166
|
+
|
167
|
+
dbg "service_init left"
|
135
168
|
end
|
136
169
|
|
137
170
|
def service_main
|
138
|
-
|
171
|
+
dbg "service_main entered"
|
139
172
|
|
140
|
-
|
141
|
-
@
|
173
|
+
dbg "rails.start_serve"
|
174
|
+
@rails.start_serve
|
142
175
|
|
143
|
-
|
176
|
+
dbg "while RUNNING"
|
144
177
|
while state == RUNNING
|
145
178
|
sleep 1
|
146
179
|
end
|
180
|
+
dbg "state !RUNNING"
|
147
181
|
|
148
|
-
|
182
|
+
dbg "rails.stop_serve"
|
183
|
+
@rails.stop_serve
|
184
|
+
|
185
|
+
dbg "service_main left"
|
149
186
|
end
|
150
187
|
|
151
188
|
def service_stop
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
#@server.stop
|
156
|
-
|
157
|
-
File.open(DEBUG_LOG_FILE,"a+") { |f| f.puts("#{Time.now} - service_stop left") }
|
189
|
+
dbg "service_stop entered"
|
190
|
+
|
191
|
+
dbg "service_stop left"
|
158
192
|
end
|
159
193
|
end
|
160
194
|
|
@@ -170,25 +204,88 @@ if ARGV[0] == 'service'
|
|
170
204
|
:port => 3000,
|
171
205
|
:mime_map => nil,
|
172
206
|
:num_procs => 20,
|
173
|
-
:timeout => 120
|
207
|
+
:timeout => 120,
|
208
|
+
:cpu => nil
|
174
209
|
}
|
175
210
|
|
176
211
|
ARGV.options do |opts|
|
177
212
|
opts.on('-r', '--root PATH', "Set the root path where your rails app resides.") { |OPTIONS[:rails_root]| }
|
178
|
-
opts.on('-e', '--environment ENV', "Rails environment to run as.") { |OPTIONS[:environment]| }
|
213
|
+
opts.on('-e', '--environment ENV', "Rails environment to run as. (default: production)") { |OPTIONS[:environment]| }
|
179
214
|
opts.on('-b', '--binding ADDR', "Address to bind to") { |OPTIONS[:ip]| }
|
180
215
|
opts.on('-p', '--port PORT', "Which port to bind to") { |OPTIONS[:port]| }
|
181
216
|
opts.on('-m', '--mime PATH', "A YAML file that lists additional MIME types") { |OPTIONS[:mime_map]| }
|
182
217
|
opts.on('-P', '--num-procs INT', "Number of processor threads to use") { |OPTIONS[:num_procs]| }
|
183
218
|
opts.on('-t', '--timeout SECONDS', "Timeout all requests after SECONDS time") { |OPTIONS[:timeout]| }
|
184
|
-
|
219
|
+
opts.on('-c', '--cpu CPU', "Bind the process to specific cpu") { |OPTIONS[:cpu]| }
|
220
|
+
|
185
221
|
opts.parse!
|
186
222
|
end
|
187
223
|
|
224
|
+
#expand RAILS_ROOT
|
225
|
+
OPTIONS[:rails_root] = File.expand_path(OPTIONS[:rails_root])
|
226
|
+
|
188
227
|
OPTIONS[:docroot] = File.expand_path(OPTIONS[:rails_root] + '/public')
|
189
228
|
|
190
|
-
|
229
|
+
# We must bind to a specific cpu?
|
230
|
+
if OPTIONS[:cpu]
|
231
|
+
Kernel32.set_affinity(Process.pid, OPTIONS[:cpu])
|
232
|
+
end
|
233
|
+
|
234
|
+
rails = MongrelRails.new(OPTIONS[:ip], OPTIONS[:port], OPTIONS[:rails_root], OPTIONS[:docroot], OPTIONS[:environment], OPTIONS[:mime_map], OPTIONS[:num_procs].to_i, OPTIONS[:timeout].to_i)
|
235
|
+
rails_svc = RailsDaemon.new(rails)
|
191
236
|
rails_svc.mainloop
|
192
237
|
|
193
|
-
|
238
|
+
elsif ARGV[0] == 'debug'
|
239
|
+
ARGV.shift
|
194
240
|
|
241
|
+
# default options
|
242
|
+
OPTIONS = {
|
243
|
+
:rails_root => Dir.pwd,
|
244
|
+
:environment => 'production',
|
245
|
+
:ip => '0.0.0.0',
|
246
|
+
:port => 3000,
|
247
|
+
:mime_map => nil,
|
248
|
+
:num_procs => 20,
|
249
|
+
:timeout => 120,
|
250
|
+
:cpu => nil
|
251
|
+
}
|
252
|
+
|
253
|
+
ARGV.options do |opts|
|
254
|
+
opts.on('-r', '--root PATH', "Set the root path where your rails app resides.") { |OPTIONS[:rails_root]| }
|
255
|
+
opts.on('-e', '--environment ENV', "Rails environment to run as.") { |OPTIONS[:environment]| }
|
256
|
+
opts.on('-b', '--binding ADDR', "Address to bind to") { |OPTIONS[:ip]| }
|
257
|
+
opts.on('-p', '--port PORT', "Which port to bind to") { |OPTIONS[:port]| }
|
258
|
+
opts.on('-m', '--mime PATH', "A YAML file that lists additional MIME types") { |OPTIONS[:mime_map]| }
|
259
|
+
opts.on('-P', '--num-procs INT', "Number of processor threads to use") { |OPTIONS[:num_procs]| }
|
260
|
+
opts.on('-t', '--timeout SECONDS', "Timeout all requests after SECONDS time") { |OPTIONS[:timeout]| }
|
261
|
+
opts.on('-c', '--cpu CPU', "Bind the process to specific cpu") { |OPTIONS[:cpu]| }
|
262
|
+
|
263
|
+
opts.parse!
|
264
|
+
end
|
265
|
+
|
266
|
+
#expand RAILS_ROOT
|
267
|
+
OPTIONS[:rails_root] = File.expand_path(OPTIONS[:rails_root])
|
268
|
+
|
269
|
+
OPTIONS[:docroot] = File.expand_path(OPTIONS[:rails_root] + '/public')
|
270
|
+
|
271
|
+
# We must bind to a specific cpu?
|
272
|
+
if OPTIONS[:cpu]
|
273
|
+
Kernel32.set_affinity(Process.pid, OPTIONS[:cpu])
|
274
|
+
end
|
275
|
+
|
276
|
+
rails = MongrelRails.new(OPTIONS[:ip], OPTIONS[:port], OPTIONS[:rails_root], OPTIONS[:docroot], OPTIONS[:environment], OPTIONS[:mime_map], OPTIONS[:num_procs].to_i, OPTIONS[:timeout].to_i)
|
277
|
+
rails.delayed_initialize
|
278
|
+
rails.start_serve
|
279
|
+
|
280
|
+
begin
|
281
|
+
sleep
|
282
|
+
rescue Interrupt
|
283
|
+
puts "graceful shutdown?"
|
284
|
+
end
|
285
|
+
|
286
|
+
begin
|
287
|
+
rails.stop_serve
|
288
|
+
rescue
|
289
|
+
end
|
290
|
+
|
291
|
+
end
|