daemons 1.1.9 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +1 -1
- data/README.md +206 -0
- data/Releases +17 -0
- data/examples/call/call.rb +13 -16
- data/examples/call/call_monitor.rb +13 -17
- data/examples/daemonize/daemonize.rb +4 -8
- data/examples/run/ctrl_crash.rb +0 -1
- data/examples/run/ctrl_custom_logfiles.rb +18 -0
- data/examples/run/ctrl_exec.rb +0 -1
- data/examples/run/ctrl_exit.rb +0 -1
- data/examples/run/ctrl_keep_pid_files.rb +1 -3
- data/examples/run/ctrl_monitor.rb +0 -1
- data/examples/run/ctrl_monitor_multiple.rb +17 -0
- data/examples/run/ctrl_multiple.rb +0 -1
- data/examples/run/ctrl_ontop.rb +0 -1
- data/examples/run/ctrl_optionparser.rb +4 -6
- data/examples/run/ctrl_proc.rb +8 -9
- data/examples/run/ctrl_proc_multiple.rb +4 -6
- data/examples/run/ctrl_proc_rand.rb +2 -4
- data/examples/run/ctrl_proc_simple.rb +0 -1
- data/examples/run/myserver.rb +0 -1
- data/examples/run/myserver_crashing.rb +5 -5
- data/examples/run/myserver_exiting.rb +2 -2
- data/examples/run/myserver_hanging.rb +4 -5
- data/examples/run/myserver_slowstop.rb +5 -6
- data/lib/daemons.rb +66 -68
- data/lib/daemons/application.rb +171 -188
- data/lib/daemons/application_group.rb +99 -92
- data/lib/daemons/change_privilege.rb +3 -3
- data/lib/daemons/cmdline.rb +43 -54
- data/lib/daemons/controller.rb +36 -53
- data/lib/daemons/daemonize.rb +54 -64
- data/lib/daemons/etc_extension.rb +3 -2
- data/lib/daemons/exceptions.rb +10 -11
- data/lib/daemons/monitor.rb +60 -62
- data/lib/daemons/pid.rb +24 -56
- data/lib/daemons/pidfile.rb +38 -40
- data/lib/daemons/pidmem.rb +5 -9
- data/lib/daemons/version.rb +3 -0
- metadata +45 -45
- data/README +0 -214
- data/Rakefile +0 -90
- data/TODO +0 -2
- data/setup.rb +0 -1360
@@ -1,65 +1,63 @@
|
|
1
1
|
|
2
2
|
module Daemons
|
3
3
|
class ApplicationGroup
|
4
|
-
|
5
4
|
attr_reader :app_name
|
6
5
|
attr_reader :script
|
7
|
-
|
6
|
+
|
8
7
|
attr_reader :monitor
|
9
|
-
|
10
|
-
#attr_reader :controller
|
11
|
-
|
8
|
+
|
9
|
+
# attr_reader :controller
|
10
|
+
|
12
11
|
attr_reader :options
|
13
|
-
|
12
|
+
|
14
13
|
attr_reader :applications
|
15
|
-
|
14
|
+
|
16
15
|
attr_accessor :controller_argv
|
17
16
|
attr_accessor :app_argv
|
18
|
-
|
17
|
+
|
19
18
|
attr_accessor :dir_mode
|
20
19
|
attr_accessor :dir
|
21
|
-
|
20
|
+
|
22
21
|
# true if the application is supposed to run in multiple instances
|
23
22
|
attr_reader :multiple
|
24
|
-
|
25
|
-
|
23
|
+
|
26
24
|
def initialize(app_name, options = {})
|
27
25
|
@app_name = app_name
|
28
26
|
@options = options
|
29
|
-
|
27
|
+
|
30
28
|
if options[:script]
|
31
29
|
@script = File.expand_path(options[:script])
|
32
30
|
end
|
33
|
-
|
34
|
-
|
31
|
+
|
32
|
+
# @controller = controller
|
35
33
|
@monitor = nil
|
36
|
-
|
37
|
-
#options = controller.options
|
38
|
-
|
34
|
+
|
35
|
+
# options = controller.options
|
36
|
+
|
39
37
|
@multiple = options[:multiple] || false
|
40
|
-
|
38
|
+
|
41
39
|
@dir_mode = options[:dir_mode] || :script
|
42
40
|
@dir = options[:dir] || ''
|
43
|
-
|
41
|
+
|
44
42
|
@keep_pid_files = options[:keep_pid_files] || false
|
45
43
|
@no_pidfiles = options[:no_pidfiles] || false
|
46
|
-
|
47
|
-
|
44
|
+
|
45
|
+
# @applications = find_applications(pidfile_dir())
|
48
46
|
@applications = []
|
49
47
|
end
|
50
|
-
|
48
|
+
|
51
49
|
# Setup the application group.
|
52
50
|
# Currently this functions calls <tt>find_applications</tt> which finds
|
53
51
|
# all running instances of the application and populates the application array.
|
54
52
|
#
|
55
53
|
def setup
|
56
|
-
@applications = find_applications(pidfile_dir
|
54
|
+
@applications = find_applications(pidfile_dir)
|
57
55
|
end
|
58
|
-
|
56
|
+
|
59
57
|
def pidfile_dir
|
60
58
|
PidFile.dir(@dir_mode, @dir, script)
|
61
|
-
end
|
62
|
-
|
59
|
+
end
|
60
|
+
|
63
61
|
def find_applications(dir)
|
64
62
|
if @no_pidfiles
|
65
63
|
return find_applications_by_app_name(app_name)
|
@@ -67,128 +65,137 @@ module Daemons
|
|
67
65
|
return find_applications_by_pidfiles(dir)
|
68
66
|
end
|
69
67
|
end
|
70
|
-
|
68
|
+
|
71
69
|
# TODO: identifiy the monitor process
|
72
70
|
def find_applications_by_app_name(app_name)
|
73
71
|
pids = []
|
74
|
-
|
72
|
+
|
75
73
|
begin
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
74
|
+
x = `ps auxw | grep -v grep | awk '{print $2, $11, $12}' | grep #{app_name}`
|
75
|
+
if x && x.chomp!
|
76
|
+
processes = x.split(/\n/).compact
|
77
|
+
processes = processes.delete_if do |p|
|
78
|
+
pid, name, add = p.split(/\s/)
|
79
|
+
# We want to make sure that the first part of the process name matches
|
80
|
+
# so that app_name matches app_name_22
|
81
|
+
|
82
|
+
app_name != name[0..(app_name.length - 1)] and not add.include?(app_name)
|
83
|
+
end
|
84
|
+
pids = processes.map { |p| p.split(/\s/)[0].to_i }
|
85
85
|
end
|
86
|
-
|
86
|
+
rescue ::Exception
|
87
87
|
end
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
return pids.map {|f|
|
88
|
+
|
89
|
+
pids.map do |f|
|
92
90
|
app = Application.new(self, {}, PidMem.existing(f))
|
93
91
|
setup_app(app)
|
94
92
|
app
|
95
|
-
|
93
|
+
end
|
96
94
|
end
|
97
|
-
|
95
|
+
|
98
96
|
def find_applications_by_pidfiles(dir)
|
99
|
-
pid_files = PidFile.find_files(dir, app_name, ! @keep_pid_files)
|
100
|
-
|
101
|
-
#pp pid_files
|
102
|
-
|
103
97
|
@monitor = Monitor.find(dir, app_name + '_monitor')
|
104
|
-
|
105
|
-
pid_files.
|
106
|
-
|
107
|
-
return pid_files.map {|f|
|
98
|
+
|
99
|
+
pid_files = PidFile.find_files(dir, app_name, ! @keep_pid_files)
|
100
|
+
pid_files.map do |f|
|
108
101
|
app = Application.new(self, {}, PidFile.existing(f))
|
109
102
|
setup_app(app)
|
110
103
|
app
|
111
|
-
|
104
|
+
end
|
112
105
|
end
|
113
|
-
|
106
|
+
|
114
107
|
def new_application(add_options = {})
|
115
|
-
if @applications.size > 0
|
108
|
+
if @applications.size > 0 && !@multiple
|
116
109
|
if options[:force]
|
117
|
-
@applications.delete_if
|
110
|
+
@applications.delete_if do |a|
|
118
111
|
unless a.running?
|
119
112
|
a.zap
|
120
113
|
true
|
121
114
|
end
|
122
|
-
|
115
|
+
end
|
123
116
|
end
|
124
|
-
|
125
|
-
|
117
|
+
|
118
|
+
fail RuntimeException.new('there is already one or more instance(s) of the program running') unless @applications.empty?
|
126
119
|
end
|
127
|
-
|
120
|
+
|
128
121
|
app = Application.new(self, add_options)
|
129
|
-
|
122
|
+
|
130
123
|
setup_app(app)
|
131
|
-
|
124
|
+
|
132
125
|
@applications << app
|
133
|
-
|
134
|
-
|
126
|
+
|
127
|
+
app
|
135
128
|
end
|
136
|
-
|
129
|
+
|
137
130
|
def setup_app(app)
|
138
131
|
app.controller_argv = @controller_argv
|
139
132
|
app.app_argv = @app_argv
|
133
|
+
if @options[:show_status_callback]
|
134
|
+
app.show_status_callback = @options[:show_status_callback]
|
135
|
+
end
|
140
136
|
end
|
141
137
|
private :setup_app
|
142
|
-
|
138
|
+
|
143
139
|
def create_monitor(an_app)
|
144
|
-
|
145
|
-
|
140
|
+
if @monitor && options[:monitor]
|
141
|
+
@monitor.stop
|
142
|
+
@monitor = nil
|
143
|
+
end
|
144
|
+
|
146
145
|
if options[:monitor]
|
147
146
|
@monitor = Monitor.new(an_app)
|
148
|
-
|
149
|
-
@monitor.start(@applications)
|
147
|
+
@monitor.start(self)
|
150
148
|
end
|
151
149
|
end
|
152
|
-
|
150
|
+
|
153
151
|
def start_all
|
154
152
|
@monitor.stop if @monitor
|
155
153
|
@monitor = nil
|
156
|
-
|
157
|
-
@applications.each
|
158
|
-
fork
|
159
|
-
a.start
|
160
|
-
|
161
|
-
|
154
|
+
|
155
|
+
@applications.each do |a|
|
156
|
+
fork do
|
157
|
+
a.start
|
158
|
+
end
|
159
|
+
end
|
162
160
|
end
|
163
|
-
|
161
|
+
|
164
162
|
def stop_all(no_wait = false)
|
165
|
-
|
166
|
-
|
163
|
+
if @monitor
|
164
|
+
@monitor.stop
|
165
|
+
@monitor = nil
|
166
|
+
setup
|
167
|
+
end
|
168
|
+
|
167
169
|
threads = []
|
168
|
-
|
169
|
-
@applications.each
|
170
|
+
|
171
|
+
@applications.each do |a|
|
170
172
|
threads << Thread.new do
|
171
173
|
a.stop(no_wait)
|
172
174
|
end
|
173
|
-
|
174
|
-
|
175
|
-
threads.each {|t| t.join}
|
175
|
+
end
|
176
|
+
|
177
|
+
threads.each { |t| t.join }
|
176
178
|
end
|
177
|
-
|
179
|
+
|
178
180
|
def reload_all
|
179
|
-
@applications.each {|a| a.reload}
|
181
|
+
@applications.each { |a| a.reload }
|
180
182
|
end
|
181
183
|
|
182
184
|
def zap_all
|
183
185
|
@monitor.stop if @monitor
|
184
|
-
|
185
|
-
@applications.each {|a| a.zap}
|
186
|
+
|
187
|
+
@applications.each { |a| a.zap }
|
186
188
|
end
|
187
|
-
|
189
|
+
|
188
190
|
def show_status
|
189
|
-
@applications.each {|a| a.show_status}
|
191
|
+
@applications.each { |a| a.show_status }
|
192
|
+
end
|
193
|
+
|
194
|
+
# Check whether at least one of the applications in the group is running. If yes, return true.
|
195
|
+
def running?
|
196
|
+
@applications.each { |a| return true if a.running? }
|
197
|
+
return false
|
190
198
|
end
|
191
199
|
|
192
200
|
end
|
193
|
-
|
194
201
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'daemons/etc_extension'
|
2
2
|
|
3
3
|
class CurrentProcess
|
4
|
-
def self.change_privilege(user, group=user)
|
4
|
+
def self.change_privilege(user, group = user)
|
5
5
|
puts "Changing process privilege to #{user}:#{group}"
|
6
|
-
|
6
|
+
|
7
7
|
uid, gid = Process.euid, Process.egid
|
8
8
|
target_uid = Etc.getpwnam(user).uid
|
9
9
|
target_gid = Etc.getgrnam(group).gid
|
@@ -16,4 +16,4 @@ class CurrentProcess
|
|
16
16
|
rescue Errno::EPERM => e
|
17
17
|
raise "Couldn't change user and group to #{user}:#{group}: #{e}"
|
18
18
|
end
|
19
|
-
end
|
19
|
+
end
|
data/lib/daemons/cmdline.rb
CHANGED
@@ -1,56 +1,52 @@
|
|
1
|
-
|
2
1
|
module Daemons
|
3
|
-
|
4
2
|
class Optparse
|
5
|
-
|
6
3
|
attr_reader :usage
|
7
4
|
|
8
5
|
def initialize(controller)
|
9
6
|
@controller = controller
|
10
7
|
@options = {}
|
11
|
-
|
8
|
+
|
12
9
|
@opts = OptionParser.new do |opts|
|
13
|
-
opts.banner =
|
14
|
-
|
10
|
+
opts.banner = ''
|
11
|
+
|
15
12
|
# opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
|
16
13
|
# @options[:verbose] = v
|
17
14
|
# end
|
18
|
-
|
19
|
-
opts.on(
|
15
|
+
|
16
|
+
opts.on('-t', '--ontop', 'Stay on top (does not daemonize)') do |t|
|
20
17
|
@options[:ontop] = t
|
21
18
|
end
|
22
|
-
|
23
|
-
opts.on(
|
19
|
+
|
20
|
+
opts.on('-f', '--force', 'Force operation') do |t|
|
24
21
|
@options[:force] = t
|
25
22
|
end
|
26
|
-
|
27
|
-
opts.on(
|
23
|
+
|
24
|
+
opts.on('-n', '--no_wait', 'Do not wait for processes to stop') do |t|
|
28
25
|
@options[:no_wait] = t
|
29
26
|
end
|
30
|
-
|
31
|
-
#opts.separator ""
|
32
|
-
#opts.separator "Specific options:"
|
33
27
|
|
34
|
-
|
35
|
-
opts.separator ""
|
36
|
-
|
28
|
+
# opts.separator ""
|
29
|
+
# opts.separator "Specific options:"
|
30
|
+
|
31
|
+
opts.separator ''
|
32
|
+
opts.separator 'Common options:'
|
37
33
|
|
38
34
|
# No argument, shows at tail. This will print an options summary
|
39
|
-
opts.on_tail(
|
40
|
-
#puts opts
|
41
|
-
|
42
|
-
controller.print_usage
|
43
|
-
|
35
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
36
|
+
# puts opts
|
37
|
+
# @usage =
|
38
|
+
controller.print_usage
|
39
|
+
|
44
40
|
exit
|
45
41
|
end
|
46
42
|
|
47
43
|
# Switch to print the version.
|
48
|
-
opts.on_tail(
|
44
|
+
opts.on_tail('--version', 'Show version') do
|
49
45
|
puts "daemons version #{Daemons::VERSION}"
|
50
46
|
exit
|
51
47
|
end
|
52
|
-
end
|
53
|
-
|
48
|
+
end
|
49
|
+
|
54
50
|
begin
|
55
51
|
@usage = @opts.to_s
|
56
52
|
rescue ::Exception # work around a bug in ruby 1.9
|
@@ -65,57 +61,50 @@ module Daemons
|
|
65
61
|
END
|
66
62
|
end
|
67
63
|
end
|
68
|
-
|
69
|
-
|
64
|
+
|
70
65
|
#
|
71
66
|
# Return a hash describing the options.
|
72
67
|
#
|
73
68
|
def parse(args)
|
74
69
|
# The options specified on the command line will be collected in *options*.
|
75
70
|
# We set default values here.
|
76
|
-
#options = {}
|
77
|
-
|
78
|
-
|
79
|
-
##pp args
|
71
|
+
# options = {}
|
72
|
+
|
73
|
+
# #pp args
|
80
74
|
@opts.parse(args)
|
81
|
-
|
82
|
-
return @options
|
83
|
-
end
|
84
75
|
|
76
|
+
@options
|
77
|
+
end
|
85
78
|
end
|
86
|
-
|
87
|
-
|
79
|
+
|
88
80
|
class Controller
|
89
|
-
|
90
81
|
def print_usage
|
91
82
|
puts "Usage: #{@app_name} <command> <options> -- <application options>"
|
92
83
|
puts
|
93
|
-
puts
|
94
|
-
puts
|
95
|
-
puts
|
96
|
-
puts
|
97
|
-
puts
|
98
|
-
puts
|
99
|
-
puts
|
100
|
-
puts
|
84
|
+
puts '* where <command> is one of:'
|
85
|
+
puts ' start start an instance of the application'
|
86
|
+
puts ' stop stop all instances of the application'
|
87
|
+
puts ' restart stop all instances and restart them afterwards'
|
88
|
+
puts ' reload send a SIGHUP to all instances of the application'
|
89
|
+
puts ' run start the application and stay on top'
|
90
|
+
puts ' zap set the application to a stopped state'
|
91
|
+
puts ' status show status (PID) of application instances'
|
101
92
|
puts
|
102
|
-
puts
|
103
|
-
|
93
|
+
puts '* and where <options> may contain several of the following:'
|
94
|
+
|
104
95
|
puts @optparse.usage
|
105
96
|
end
|
106
|
-
|
97
|
+
|
107
98
|
def catch_exceptions(&block)
|
108
99
|
begin
|
109
100
|
block.call
|
110
101
|
rescue CmdException, OptionParser::ParseError => e
|
111
|
-
puts "ERROR: #{e
|
102
|
+
puts "ERROR: #{e}"
|
112
103
|
puts
|
113
|
-
print_usage
|
104
|
+
print_usage
|
114
105
|
rescue RuntimeException => e
|
115
|
-
puts "ERROR: #{e
|
106
|
+
puts "ERROR: #{e}"
|
116
107
|
end
|
117
108
|
end
|
118
|
-
|
119
109
|
end
|
120
|
-
|
121
110
|
end
|