summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Moore <tmoore@incrementalism.net>2013-01-30 13:45:32 +1100
committerJames Tucker <jftucker@gmail.com>2013-02-07 18:34:01 -0800
commit3316749e3cd0b2bf43400e215f62b06499f00dbc (patch)
treea4243ff176cfaeae29b7f6dfaa649a9bfca146ed
parentdcc7e6fa5106e1e8129f4bbe21f7e1607dbf5197 (diff)
downloadrack-3316749e3cd0b2bf43400e215f62b06499f00dbc.tar.gz
Stop overwriting existing pidfiles.
A race condition can arise when two servers are started simultaneously. Both instances may complete the check for an existing pidfile before either one writes it. Now the pidfile is opened with ::File::EXCL, which raises an error if the file already exists. This error is handled by retrying the check and the write.
-rw-r--r--lib/rack/server.rb5
-rw-r--r--test/spec_server.rb16
2 files changed, 20 insertions, 1 deletions
diff --git a/lib/rack/server.rb b/lib/rack/server.rb
index b385d4bd..dfaed3fc 100644
--- a/lib/rack/server.rb
+++ b/lib/rack/server.rb
@@ -329,8 +329,11 @@ module Rack
end
def write_pid
- ::File.open(options[:pid], 'w'){ |f| f.write("#{Process.pid}") }
+ ::File.open(options[:pid], ::File::CREAT | ::File::EXCL | ::File::WRONLY ){ |f| f.write("#{Process.pid}") }
at_exit { ::File.delete(options[:pid]) if ::File.exist?(options[:pid]) }
+ rescue Errno::EEXIST
+ check_pid!
+ retry
end
def check_pid!
diff --git a/test/spec_server.rb b/test/spec_server.rb
index 82495bd8..44d4bcbb 100644
--- a/test/spec_server.rb
+++ b/test/spec_server.rb
@@ -110,6 +110,22 @@ describe Rack::Server do
server.send(:pidfile_process_status).should.eql :not_owned
end
+ should "not write pid file when it is created after check" do
+ pidfile = Tempfile.open('pidfile') { |f| break f }.path
+ ::File.delete(pidfile)
+ server = Rack::Server.new(:pid => pidfile)
+ ::File.open(pidfile, 'w') { |f| f.write(1) }
+ with_stderr do |err|
+ should.raise(SystemExit) do
+ server.send(:write_pid)
+ end
+ err.rewind
+ output = err.read
+ output.should.match(/already running/)
+ output.should.include? pidfile
+ end
+ end
+
should "inform the user about existing pidfiles with running processes" do
pidfile = Tempfile.open('pidfile') { |f| f.write(1); break f }.path
server = Rack::Server.new(:pid => pidfile)