Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 13
- Log:
Initial import of Typo 2.6.0 sources from a downloaded Tarball.
Typo is a Ruby On Rails based blog engine.
- Author:
- adh
- Date:
- Sat Jul 22 22:25:02 +0100 2006
- Size:
- 4392 Bytes
- Properties:
- Property svn:executable is set
1 | #!/usr/local/bin/ruby |
2 | |
3 | require 'optparse' |
4 | require 'net/http' |
5 | require 'uri' |
6 | |
7 | def nudge(url, iterations) |
8 | print "Nudging #{url}: " |
9 | iterations.times { Net::HTTP.get_response(URI.parse(url)); print "."; STDOUT.flush } |
10 | puts |
11 | end |
12 | |
13 | if RUBY_PLATFORM =~ /mswin32/ then abort("Reaper is only for Unix") end |
14 | |
15 | class ProgramProcess |
16 | class << self |
17 | def process_keywords(action, *keywords) |
18 | processes = keywords.collect { |keyword| find_by_keyword(keyword) }.flatten |
19 | |
20 | if processes.empty? |
21 | puts "Couldn't find any process matching: #{keywords.join(" or ")}" |
22 | else |
23 | processes.each do |process| |
24 | puts "#{action.capitalize}ing #{process}" |
25 | process.send(action) |
26 | end |
27 | end |
28 | end |
29 | |
30 | def find_by_keyword(keyword) |
31 | process_lines_with_keyword(keyword).split("\n").collect { |line| |
32 | next if line.include?("inq") || line.include?("ps ax") || line.include?("grep") |
33 | pid, *command = line.split |
34 | new(pid, command.join(" ")) |
35 | }.compact |
36 | end |
37 | |
38 | private |
39 | def process_lines_with_keyword(keyword) |
40 | `ps ax -o 'pid command' | grep #{keyword}` |
41 | end |
42 | end |
43 | |
44 | def initialize(pid, command) |
45 | @pid, @command = pid, command |
46 | end |
47 | |
48 | def find |
49 | end |
50 | |
51 | def reload |
52 | `kill -s HUP #{@pid}` |
53 | end |
54 | |
55 | def graceful |
56 | `kill -s TERM #{@pid}` |
57 | end |
58 | |
59 | def kill |
60 | `kill -9 #{@pid}` |
61 | end |
62 | |
63 | def usr1 |
64 | `kill -s USR1 #{@pid}` |
65 | end |
66 | |
67 | def to_s |
68 | "[#{@pid}] #{@command}" |
69 | end |
70 | end |
71 | |
72 | OPTIONS = { |
73 | :action => "graceful", |
74 | :dispatcher => File.expand_path(File.dirname(__FILE__) + '/../../public/dispatch.fcgi'), |
75 | :spinner => File.expand_path(File.dirname(__FILE__) + '/spinner'), |
76 | :toggle_spin => true, |
77 | :iterations => 10, |
78 | :nudge => false |
79 | } |
80 | |
81 | ARGV.options do |opts| |
82 | opts.banner = "Usage: reaper [options]" |
83 | |
84 | opts.separator "" |
85 | |
86 | opts.on <<-EOF |
87 | Description: |
88 | The reaper is used to reload, gracefully exit, and forcefully exit FCGI processes |
89 | running a Rails Dispatcher. This is commonly done when a new version of the application |
90 | is available, so the existing processes can be updated to use the latest code. |
91 | |
92 | The reaper actions are: |
93 | |
94 | * reload : Only reloads the application, but not the framework (like the development environment) |
95 | * graceful: Marks all of the processes for exit after the next request |
96 | * kill : Forcefully exists all processes regardless of whether they're currently serving a request |
97 | |
98 | Graceful exist is the most common and default action. But since the processes won't exist until after |
99 | their next request, it's often necessary to ensure that such a request occurs right after they've been |
100 | marked. That's what nudging is for. |
101 | |
102 | A nudge is simply a request to a URL where the dispatcher is serving. You should perform one nudge per |
103 | FCGI process you have running if they're setup in a round-robin. Be sure to do one nudge per FCGI process |
104 | across all your servers. So three servers with 10 processes each should nudge 30 times to be sure all processes |
105 | are restarted. |
106 | |
107 | Examples: |
108 | reaper -a reload |
109 | reaper -n http://www.example.com -i 10 # gracefully exit, nudge 10 times |
110 | EOF |
111 | |
112 | opts.on(" Options:") |
113 | |
114 | opts.on("-a", "--action=name", "reload|graceful|kill (default: #{OPTIONS[:action]})", String) { |OPTIONS[:action]| } |
115 | opts.on("-d", "--dispatcher=path", "default: #{OPTIONS[:dispatcher]}", String) { |OPTIONS[:dispatcher]| } |
116 | opts.on("-s", "--spinner=path", "default: #{OPTIONS[:spinner]}", String) { |OPTIONS[:spinner]| } |
117 | opts.on("-t", "--toggle-spin", "Whether to send a USR1 to the spinner before and after the reaping (default: true)") { |OPTIONS[:toggle_spin]| } |
118 | opts.on("-n", "--nudge=url", "Should point to URL that's handled by the FCGI process", String) { |OPTIONS[:nudge]| } |
119 | opts.on("-i", "--iterations=number", "One nudge per FCGI process running (default: #{OPTIONS[:iterations]})", Integer) { |OPTIONS[:iterations]| } |
120 | |
121 | opts.separator "" |
122 | |
123 | opts.on("-h", "--help", "Show this help message.") { puts opts; exit } |
124 | |
125 | opts.parse! |
126 | end |
127 | |
128 | ProgramProcess.process_keywords("usr1", OPTIONS[:spinner]) if OPTIONS[:toggle_spin] |
129 | ProgramProcess.process_keywords(OPTIONS[:action], OPTIONS[:dispatcher]) |
130 | nudge(OPTIONS[:nudge], OPTIONS[:iterations]) if OPTIONS[:nudge] |
131 | ProgramProcess.process_keywords("usr1", OPTIONS[:spinner]) if OPTIONS[:toggle_spin] |