5 if RUBY_PLATFORM =~
/(:?mswin|mingw)/ then abort("Reaper is only for Unix") end
9 # Searches for all processes matching the given keywords, and then invokes
10 # a specific action on each of them. This is useful for (e.g.) reloading a
13 # Killer.process(:reload, "/tmp/pids", "dispatcher.*.pid")
14 def process(action
, pid_path
, pattern
, keyword
)
15 new(pid_path
, pattern
, keyword
).process(action
)
18 # Forces the (rails) application to reload by sending a +HUP+ signal to the
24 # Force the (rails) application to restart by sending a +USR2+ signal to the
30 # Forces the (rails) application to gracefully terminate by sending a
31 # +TERM+ signal to the process.
36 # Forces the (rails) application to terminate immediately by sending a -9
37 # signal to the process.
42 # Send a +USR1+ signal to the process.
48 def initialize(pid_path
, pattern
, keyword
=nil)
49 @pid_path, @pattern, @keyword = pid_path
, pattern
, keyword
56 warn
"Couldn't find any pid file in '#{@pid_path}' matching '#{@pattern}'"
57 warn
"(also looked for processes matching #{@keyword.inspect})" if @keyword
60 puts
"#{action.capitalize}ing #{pid}"
61 self.class.send(action
, pid
)
64 delete_pid_files
if terminating
?(action
)
69 def terminating
?(action
)
70 [ "kill", "graceful" ].include?(action
)
76 find_processes_via_grep
78 files
.collect
{ |pid_file
| File
.read(pid_file
).to_i
}
82 def find_processes_via_grep
83 lines
= `ps axww -o 'pid command' | grep #{@keyword}`.split(/\n/).
84 reject
{ |line
| line
=~
/inq|ps axww|grep|spawn-fcgi|spawner|reaper/ }
85 lines
.map
{ |line
| line
[/^\s*(\d+)/, 1].to_i
}
89 pid_files
.each
{ |pid_file
| File
.delete(pid_file
) }
93 Dir
.glob(@pid_path + "/" + @pattern)
100 :pid_path => File
.expand_path(RAILS_ROOT
+ '/tmp/pids'),
101 :pattern => "dispatch.[0-9]*.pid",
102 :dispatcher => File
.expand_path("#{RAILS_ROOT}/public/dispatch.fcgi")
105 ARGV.options
do |opts
|
106 opts
.banner
= "Usage: reaper [options]"
112 The reaper is used to restart, reload, gracefully exit, and forcefully exit processes
113 running a Rails Dispatcher (or any other process responding to the same signals). This
114 is commonly done when a new version of the application is available, so the existing
115 processes can be updated to use the latest code.
117 It uses pid files to work on the processes and by default assume them to be located
118 in RAILS_ROOT/tmp/pids.
120 The reaper actions are:
122 * restart : Restarts the application by reloading both application and framework code
123 * reload : Only reloads the application, but not the framework (like the development environment)
124 * graceful: Marks all of the processes for exit after the next request
125 * kill : Forcefully exists all processes regardless of whether they're currently serving a request
127 Restart is the most common and default action.
130 reaper # restarts the default dispatchers
131 reaper -a reload # reload the default dispatchers
132 reaper -a kill -r *.pid # kill all processes that keep pids in tmp/pids
137 opts
.on("-a", "--action=name", "reload|graceful|kill (default: #{OPTIONS[:action]})", String
) { |v
| OPTIONS
[:action] = v
}
138 opts
.on("-p", "--pidpath=path", "default: #{OPTIONS[:pid_path]}", String
) { |v
| OPTIONS
[:pid_path] = v
}
139 opts
.on("-r", "--pattern=pattern", "default: #{OPTIONS[:pattern]}", String
) { |v
| OPTIONS
[:pattern] = v
}
140 opts
.on("-d", "--dispatcher=path", "DEPRECATED. default: #{OPTIONS[:dispatcher]}", String
) { |v
| OPTIONS
[:dispatcher] = v
}
144 opts
.on("-h", "--help", "Show this help message.") { puts opts
; exit
}
149 Killer
.process(OPTIONS
[:action], OPTIONS
[:pid_path], OPTIONS
[:pattern], OPTIONS
[:dispatcher])