forked from macournoyer/thin
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add cluster support through the -s option in the thin script, start 3…
… thins like this: thin start -s3 -p3000 3 thin servers will be started on port 3000, 3001, 3002, also the port number will be injected in the pid and log filenames.
- Loading branch information
1 parent
31d7fe1
commit 6a77256
Showing
8 changed files
with
241 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
module Thin | ||
# Control a set of servers. Generate start and stop commands and run them. | ||
class Cluster | ||
include Logging | ||
|
||
class << self | ||
# Script to run | ||
attr_accessor :thin_script | ||
end | ||
self.thin_script = 'thin' | ||
|
||
# Number of servers in the cluster. | ||
attr_accessor :size | ||
|
||
# Command line options passed to the thin script | ||
attr_accessor :options | ||
|
||
# Create a new cluster of servers launched using +options+. | ||
def initialize(options) | ||
@options = options.merge(:daemonize => true) | ||
@size = @options.delete(:servers) | ||
end | ||
|
||
def first_port; @options[:port] end | ||
def address; @options[:address] end | ||
def pid_file; File.expand_path File.join(@options[:chdir], @options[:pid]) end | ||
def log_file; File.expand_path File.join(@options[:chdir], @options[:log]) end | ||
|
||
# Start the servers | ||
def start | ||
with_each_server { |port| start_on_port port } | ||
end | ||
|
||
# Start the server on a single port | ||
def start_on_port(port) | ||
log "Starting #{address}:#{port} ... " | ||
|
||
run :start, @options, port | ||
end | ||
|
||
# Stop the servers | ||
def stop | ||
with_each_server { |port| stop_on_port port } | ||
end | ||
|
||
# Stop the server running on +port+ | ||
def stop_on_port(port) | ||
log "Stopping #{address}:#{port} ... " | ||
|
||
run :stop, @options, port | ||
end | ||
|
||
# Stop and start the servers. | ||
def restart | ||
stop | ||
sleep 0.1 # Let's breath a bit shall we ? | ||
start | ||
end | ||
|
||
def log_file_for(port) | ||
include_port_number log_file, port | ||
end | ||
|
||
def pid_file_for(port) | ||
include_port_number pid_file, port | ||
end | ||
|
||
def pid_for(port) | ||
File.read(pid_file_for(port)).chomp.to_i | ||
end | ||
|
||
private | ||
# Send the command to the +thin+ script | ||
def run(cmd, options, port) | ||
shell_cmd = shellify(cmd, options.merge(:pid => pid_file_for(port), :log => log_file_for(port))) | ||
trace shell_cmd | ||
log `#{shell_cmd}` | ||
end | ||
|
||
# Turn into a runnable shell command | ||
def shellify(cmd, options) | ||
shellified_options = options.inject([]) do |args, (name, value)| | ||
args << case value | ||
when NilClass | ||
when TrueClass then "--#{name}" | ||
else "--#{name.to_s.tr('_', '-')}=#{value.inspect}" | ||
end | ||
end | ||
"#{self.class.thin_script} #{cmd} #{shellified_options.compact.join(' ')}" | ||
end | ||
|
||
def with_each_server | ||
@size.times { |n| yield first_port + n } | ||
end | ||
|
||
# Add the port numbers in the filename | ||
# so each instance get its own file | ||
def include_port_number(path, port) | ||
raise ArgumentError, "filename '#{path}' must include an extension" unless path =~ /\./ | ||
path.gsub(/\.(.+)$/) { ".#{port}.#{$1}" } | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
require File.dirname(__FILE__) + '/spec_helper' | ||
|
||
describe Cluster do | ||
before do | ||
Thin::Cluster.thin_script = File.dirname(__FILE__) + '/../bin/thin' | ||
@cluster = Thin::Cluster.new(:chdir => File.dirname(__FILE__) + '/rails_app', | ||
:address => '0.0.0.0', | ||
:port => 3000, | ||
:servers => 3, | ||
:timeout => 10, | ||
:log => 'thin.log', | ||
:pid => 'thin.pid' | ||
) | ||
@cluster.silent = true | ||
end | ||
|
||
it 'should include port number in file names' do | ||
@cluster.send(:include_port_number, 'thin.log', 3000).should == 'thin.3000.log' | ||
@cluster.send(:include_port_number, 'thin.pid', 3000).should == 'thin.3000.pid' | ||
proc { @cluster.send(:include_port_number, 'thin', 3000) }.should raise_error(ArgumentError) | ||
end | ||
|
||
it 'should call each server' do | ||
calls = [] | ||
@cluster.send(:with_each_server) do |port| | ||
calls << port | ||
end | ||
calls.should == [3000, 3001, 3002] | ||
end | ||
|
||
it 'should shellify command' do | ||
out = @cluster.send(:shellify, :start, :port => 3000, :daemonize => true, :log => 'hi.log', :pid => nil) | ||
out.should include('--port=3000', '--daemonize', '--log="hi.log"', 'thin start --') | ||
out.should_not include('--pid=') | ||
end | ||
|
||
it 'should absolutize file path' do | ||
@cluster.pid_file_for(3000).should == File.expand_path(File.dirname(__FILE__) + "/rails_app/thin.3000.pid") | ||
end | ||
|
||
it 'should start on specified port' do | ||
@cluster.start_on_port 3000 | ||
|
||
File.exist?(@cluster.pid_file_for(3000)).should be_true | ||
File.exist?(@cluster.log_file_for(3000)).should be_true | ||
end | ||
|
||
it 'should stop on specified port' do | ||
@cluster.start_on_port 3000 | ||
@cluster.stop_on_port 3000 | ||
|
||
File.exist?(@cluster.pid_file_for(3000)).should be_false | ||
end | ||
|
||
after do | ||
3000.upto(3003) do |port| | ||
Process.kill 9, @cluster.pid_for(port) rescue nil | ||
File.delete @cluster.pid_file_for(port) rescue nil | ||
File.delete @cluster.log_file_for(port) rescue nil | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters