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
data/lib/daemons/controller.rb
CHANGED
@@ -1,70 +1,57 @@
|
|
1
1
|
|
2
2
|
module Daemons
|
3
3
|
class Controller
|
4
|
-
|
5
4
|
attr_reader :app_name
|
6
|
-
|
5
|
+
|
7
6
|
attr_reader :group
|
8
|
-
|
7
|
+
|
9
8
|
attr_reader :options
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
'start',
|
14
|
-
'stop',
|
15
|
-
'restart',
|
16
|
-
'run',
|
17
|
-
'zap',
|
18
|
-
'reload',
|
19
|
-
'status'
|
20
|
-
]
|
21
|
-
|
9
|
+
|
10
|
+
COMMANDS = %w(start stop restart run zap reload status)
|
11
|
+
|
22
12
|
def initialize(options = {}, argv = [])
|
23
13
|
@options = options
|
24
14
|
@argv = argv
|
25
|
-
|
15
|
+
|
26
16
|
# Allow an app_name to be specified. If not specified use the
|
27
17
|
# basename of the script.
|
28
18
|
@app_name = options[:app_name]
|
29
|
-
|
19
|
+
|
30
20
|
if options[:script]
|
31
21
|
@script = File.expand_path(options[:script])
|
32
|
-
|
22
|
+
|
33
23
|
@app_name ||= File.split(@script)[1]
|
34
24
|
end
|
35
|
-
|
25
|
+
|
36
26
|
@app_name ||= 'unknown_application'
|
37
|
-
|
27
|
+
|
38
28
|
@command, @controller_part, @app_part = Controller.split_argv(argv)
|
39
|
-
|
40
|
-
|
41
|
-
|
29
|
+
|
30
|
+
# @options[:dir_mode] ||= :script
|
31
|
+
|
42
32
|
@optparse = Optparse.new(self)
|
43
33
|
end
|
44
|
-
|
45
|
-
|
34
|
+
|
46
35
|
# This function is used to do a final update of the options passed to the application
|
47
36
|
# before they are really used.
|
48
37
|
#
|
49
38
|
# Note that this function should only update <tt>@options</tt> and no other variables.
|
50
39
|
#
|
51
40
|
def setup_options
|
52
|
-
|
41
|
+
# @options[:ontop] ||= true
|
53
42
|
end
|
54
|
-
|
43
|
+
|
55
44
|
def run
|
56
|
-
@options.update @optparse.parse(@controller_part).delete_if {|k,v| !v}
|
57
|
-
|
58
|
-
setup_options
|
59
|
-
|
60
|
-
#pp @options
|
45
|
+
@options.update @optparse.parse(@controller_part).delete_if { |k, v| !v }
|
46
|
+
|
47
|
+
setup_options
|
61
48
|
|
62
49
|
@group = ApplicationGroup.new(@app_name, @options)
|
63
50
|
@group.controller_argv = @controller_part
|
64
51
|
@group.app_argv = @app_part
|
65
|
-
|
52
|
+
|
66
53
|
@group.setup
|
67
|
-
|
54
|
+
|
68
55
|
case @command
|
69
56
|
when 'start'
|
70
57
|
@group.new_application.start
|
@@ -79,7 +66,7 @@ module Daemons
|
|
79
66
|
sleep(1)
|
80
67
|
@group.start_all
|
81
68
|
else
|
82
|
-
puts "
|
69
|
+
$stderr.puts "#{@group.app_name}: warning: no instances running. Starting..."
|
83
70
|
@group.new_application.start
|
84
71
|
end
|
85
72
|
when 'reload'
|
@@ -89,21 +76,18 @@ module Daemons
|
|
89
76
|
when 'status'
|
90
77
|
unless @group.applications.empty?
|
91
78
|
@group.show_status
|
79
|
+
exit 3 if not @group.running? # exit with status 3 to indicate that no apps are running
|
92
80
|
else
|
93
|
-
puts "#{@group.app_name}: no instances running"
|
81
|
+
$stderr.puts "#{@group.app_name}: no instances running"
|
82
|
+
exit 3 # exit with status 3 to indicate that no apps are running
|
94
83
|
end
|
95
84
|
when nil
|
96
|
-
|
97
|
-
#puts "ERROR: No command given"; puts
|
98
|
-
|
99
|
-
#print_usage()
|
100
|
-
#raise('usage function not implemented')
|
85
|
+
fail CmdException.new('no command given')
|
101
86
|
else
|
102
|
-
|
87
|
+
fail Error.new("command '#{@command}' not implemented")
|
103
88
|
end
|
104
89
|
end
|
105
|
-
|
106
|
-
|
90
|
+
|
107
91
|
# Split an _argv_ array.
|
108
92
|
# +argv+ is assumed to be in the following format:
|
109
93
|
# ['command', 'controller option 1', 'controller option 2', ..., '--', 'app option 1', ...]
|
@@ -113,28 +97,27 @@ module Daemons
|
|
113
97
|
# *Returns*: the command as a string, the controller options as an array, the appliation options
|
114
98
|
# as an array
|
115
99
|
#
|
116
|
-
def
|
100
|
+
def self.split_argv(argv)
|
117
101
|
argv = argv.dup
|
118
|
-
|
102
|
+
|
119
103
|
command = nil
|
120
104
|
controller_part = []
|
121
105
|
app_part = []
|
122
|
-
|
106
|
+
|
123
107
|
if COMMANDS.include? argv[0]
|
124
108
|
command = argv.shift
|
125
109
|
end
|
126
|
-
|
110
|
+
|
127
111
|
if i = argv.index('--')
|
128
112
|
# Handle the case where no controller options are given, just
|
129
113
|
# options after "--" as well (i == 0)
|
130
|
-
controller_part = (i == 0 ? [] : argv[0..i-1])
|
131
|
-
app_part = argv[i+1..-1]
|
114
|
+
controller_part = (i == 0 ? [] : argv[0..i - 1])
|
115
|
+
app_part = argv[i + 1..-1]
|
132
116
|
else
|
133
117
|
controller_part = argv[0..-1]
|
134
118
|
end
|
135
|
-
|
136
|
-
|
119
|
+
|
120
|
+
[command, controller_part, app_part]
|
137
121
|
end
|
138
122
|
end
|
139
|
-
|
140
123
|
end
|
data/lib/daemons/daemonize.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Daemonize
|
2
|
-
|
3
2
|
# Try to fork if at all possible retrying every 5 sec if the
|
4
3
|
# maximum process limit for the system has been reached
|
5
4
|
def safefork
|
@@ -18,152 +17,143 @@ module Daemonize
|
|
18
17
|
end
|
19
18
|
end
|
20
19
|
module_function :safefork
|
21
|
-
|
22
|
-
|
20
|
+
|
23
21
|
# Simulate the daemonization process (:ontop mode)
|
24
|
-
# NOTE: STDOUT and STDERR will not be redirected to the logfile,
|
22
|
+
# NOTE: STDOUT and STDERR will not be redirected to the logfile,
|
25
23
|
# because in :ontop mode, we normally want to see the output
|
26
|
-
def simulate(logfile_name = nil)
|
24
|
+
def simulate(logfile_name = nil, app_name = nil)
|
25
|
+
$0 = app_name if app_name
|
26
|
+
|
27
27
|
# Release old working directory
|
28
|
-
Dir.chdir
|
28
|
+
Dir.chdir '/'
|
29
|
+
|
30
|
+
close_io
|
29
31
|
|
30
|
-
|
32
|
+
# Free STDIN and point it to somewhere sensible
|
33
|
+
begin; STDIN.reopen '/dev/null'; rescue ::Exception; end
|
31
34
|
|
32
|
-
#
|
33
|
-
|
35
|
+
# Split rand streams between spawning and daemonized process
|
36
|
+
srand
|
34
37
|
end
|
35
38
|
module_function :simulate
|
36
|
-
|
37
|
-
|
39
|
+
|
38
40
|
# Call a given block as a daemon
|
39
41
|
def call_as_daemon(block, logfile_name = nil, app_name = nil)
|
40
42
|
# we use a pipe to return the PID of the daemon
|
41
43
|
rd, wr = IO.pipe
|
42
|
-
|
44
|
+
|
43
45
|
if tmppid = safefork
|
44
46
|
# in the parent
|
45
|
-
|
47
|
+
|
46
48
|
wr.close
|
47
49
|
pid = rd.read.to_i
|
48
50
|
rd.close
|
49
|
-
|
51
|
+
|
50
52
|
Process.waitpid(tmppid)
|
51
|
-
|
53
|
+
|
52
54
|
return pid
|
53
55
|
else
|
54
56
|
# in the child
|
55
|
-
|
57
|
+
|
56
58
|
rd.close
|
57
|
-
|
59
|
+
|
58
60
|
# Detach from the controlling terminal
|
59
61
|
unless sess_id = Process.setsid
|
60
|
-
|
62
|
+
fail Daemons.RuntimeException.new('cannot detach from controlling terminal')
|
61
63
|
end
|
62
|
-
|
64
|
+
|
63
65
|
# Prevent the possibility of acquiring a controlling terminal
|
64
66
|
trap 'SIGHUP', 'IGNORE'
|
65
67
|
exit if pid = safefork
|
66
|
-
|
68
|
+
|
67
69
|
wr.write Process.pid
|
68
70
|
wr.close
|
69
|
-
|
71
|
+
|
70
72
|
$0 = app_name if app_name
|
71
|
-
|
73
|
+
|
72
74
|
# Release old working directory
|
73
|
-
Dir.chdir
|
74
|
-
|
75
|
-
close_io
|
75
|
+
Dir.chdir '/'
|
76
|
+
|
77
|
+
close_io
|
78
|
+
|
79
|
+
redirect_io(logfile_name)
|
76
80
|
|
77
|
-
redirect_io(logfile_name)
|
78
|
-
|
79
81
|
# Split rand streams between spawning and daemonized process
|
80
82
|
srand
|
81
|
-
|
83
|
+
|
82
84
|
block.call
|
83
|
-
|
85
|
+
|
84
86
|
exit
|
85
87
|
end
|
86
88
|
end
|
87
89
|
module_function :call_as_daemon
|
88
|
-
|
89
|
-
|
90
|
+
|
90
91
|
# Transform the current process into a daemon
|
91
92
|
def daemonize(logfile_name = nil, app_name = nil)
|
92
93
|
# Fork and exit from the parent
|
93
|
-
safefork
|
94
|
+
safefork && exit
|
94
95
|
|
95
96
|
# Detach from the controlling terminal
|
96
97
|
unless sess_id = Process.setsid
|
97
|
-
|
98
|
+
fail Daemons.RuntimeException.new('cannot detach from controlling terminal')
|
98
99
|
end
|
99
100
|
|
100
101
|
# Prevent the possibility of acquiring a controlling terminal
|
101
102
|
trap 'SIGHUP', 'IGNORE'
|
102
103
|
exit if pid = safefork
|
103
|
-
|
104
|
+
|
104
105
|
$0 = app_name if app_name
|
105
|
-
|
106
|
+
|
106
107
|
# Release old working directory
|
107
|
-
Dir.chdir
|
108
|
+
Dir.chdir '/'
|
108
109
|
|
109
|
-
close_io
|
110
|
+
close_io
|
110
111
|
|
111
112
|
redirect_io(logfile_name)
|
112
|
-
|
113
|
+
|
113
114
|
# Split rand streams between spawning and daemonized process
|
114
115
|
srand
|
115
|
-
|
116
|
-
|
116
|
+
|
117
|
+
sess_id
|
117
118
|
end
|
118
119
|
module_function :daemonize
|
119
|
-
|
120
|
-
|
121
|
-
def close_io()
|
120
|
+
|
121
|
+
def close_io
|
122
122
|
# Make sure all input/output streams are closed
|
123
123
|
# Part I: close all IO objects (except for STDIN/STDOUT/STDERR)
|
124
124
|
ObjectSpace.each_object(IO) do |io|
|
125
125
|
unless [STDIN, STDOUT, STDERR].include?(io)
|
126
|
-
|
127
|
-
unless io.closed?
|
128
|
-
io.close
|
129
|
-
end
|
130
|
-
rescue ::Exception
|
131
|
-
end
|
126
|
+
io.close rescue nil
|
132
127
|
end
|
133
128
|
end
|
134
|
-
|
129
|
+
|
135
130
|
# Make sure all input/output streams are closed
|
136
131
|
# Part II: close all file decriptors (except for STDIN/STDOUT/STDERR)
|
137
|
-
|
138
|
-
|
139
|
-
next if io.fileno < 3
|
140
|
-
io.close
|
132
|
+
3.upto(8192) do |i|
|
133
|
+
IO.for_fd(i).close rescue nil
|
141
134
|
end
|
142
135
|
end
|
143
136
|
module_function :close_io
|
144
|
-
|
145
|
-
|
137
|
+
|
146
138
|
# Free STDIN/STDOUT/STDERR file descriptors and
|
147
139
|
# point them somewhere sensible
|
148
140
|
def redirect_io(logfile_name)
|
149
|
-
begin; STDIN.reopen
|
150
|
-
|
141
|
+
begin; STDIN.reopen '/dev/null'; rescue ::Exception; end
|
142
|
+
|
151
143
|
if logfile_name
|
152
144
|
begin
|
153
|
-
STDOUT.reopen logfile_name,
|
145
|
+
STDOUT.reopen logfile_name, 'a'
|
154
146
|
File.chmod(0644, logfile_name)
|
155
147
|
STDOUT.sync = true
|
156
148
|
rescue ::Exception
|
157
|
-
begin; STDOUT.reopen
|
149
|
+
begin; STDOUT.reopen '/dev/null'; rescue ::Exception; end
|
158
150
|
end
|
159
151
|
else
|
160
|
-
begin; STDOUT.reopen
|
152
|
+
begin; STDOUT.reopen '/dev/null'; rescue ::Exception; end
|
161
153
|
end
|
162
|
-
|
154
|
+
|
163
155
|
begin; STDERR.reopen STDOUT; rescue ::Exception; end
|
164
156
|
STDERR.sync = true
|
165
157
|
end
|
166
158
|
module_function :redirect_io
|
167
|
-
|
168
|
-
|
169
159
|
end
|
@@ -2,11 +2,12 @@ require 'etc'
|
|
2
2
|
|
3
3
|
Etc.instance_eval do
|
4
4
|
def groupname(gid)
|
5
|
-
Etc.group {|e| return e.name if gid == e.gid }
|
5
|
+
Etc.group { |e| return e.name if gid == e.gid }
|
6
6
|
nil
|
7
7
|
end
|
8
|
+
|
8
9
|
def username(uid)
|
9
|
-
Etc.passwd {|e| return e.name if uid == e.uid }
|
10
|
+
Etc.passwd { |e| return e.name if uid == e.uid }
|
10
11
|
nil
|
11
12
|
end
|
12
13
|
end
|
data/lib/daemons/exceptions.rb
CHANGED
@@ -1,28 +1,27 @@
|
|
1
1
|
|
2
2
|
module Daemons
|
3
|
-
|
4
3
|
class Exception < ::RuntimeError
|
5
4
|
end
|
6
|
-
|
5
|
+
|
7
6
|
class RuntimeException < Exception
|
8
7
|
end
|
9
|
-
|
8
|
+
|
10
9
|
class CmdException < Exception
|
11
10
|
end
|
12
|
-
|
11
|
+
|
13
12
|
class Error < Exception
|
14
13
|
end
|
15
|
-
|
14
|
+
|
16
15
|
class SystemError < Error
|
17
|
-
|
18
16
|
attr_reader :system_error
|
19
|
-
|
17
|
+
|
20
18
|
def initialize(msg, system_error)
|
21
19
|
super(msg)
|
22
|
-
|
20
|
+
|
23
21
|
@system_error = system_error
|
24
22
|
end
|
25
|
-
|
26
23
|
end
|
27
|
-
|
28
|
-
|
24
|
+
|
25
|
+
class TimeoutError < Error
|
26
|
+
end
|
27
|
+
end
|
data/lib/daemons/monitor.rb
CHANGED
@@ -1,77 +1,78 @@
|
|
1
|
+
require 'daemons/exceptions'
|
1
2
|
|
2
3
|
module Daemons
|
3
|
-
|
4
4
|
require 'daemons/daemonize'
|
5
|
-
|
5
|
+
|
6
6
|
class Monitor
|
7
|
-
|
8
7
|
def self.find(dir, app_name)
|
9
8
|
pid = PidFile.find_files(dir, app_name, false)[0]
|
10
|
-
|
9
|
+
|
11
10
|
if pid
|
12
11
|
pid = PidFile.existing(pid)
|
13
|
-
|
12
|
+
|
14
13
|
unless PidFile.running?(pid.pid)
|
15
14
|
begin; pid.cleanup; rescue ::Exception; end
|
16
15
|
return
|
17
16
|
end
|
18
|
-
|
19
|
-
monitor =
|
20
|
-
|
17
|
+
|
18
|
+
monitor = allocate
|
19
|
+
|
21
20
|
monitor.instance_variable_set(:@pid, pid)
|
22
|
-
|
21
|
+
|
23
22
|
return monitor
|
24
23
|
end
|
25
|
-
|
26
|
-
|
24
|
+
|
25
|
+
nil
|
27
26
|
end
|
28
|
-
|
29
|
-
|
27
|
+
|
30
28
|
def initialize(an_app)
|
31
29
|
@app = an_app
|
32
30
|
@app_name = an_app.group.app_name + '_monitor'
|
33
|
-
|
31
|
+
|
34
32
|
if an_app.pidfile_dir
|
35
33
|
@pid = PidFile.new(an_app.pidfile_dir, @app_name, false)
|
36
34
|
else
|
37
35
|
@pid = PidMem.new
|
38
36
|
end
|
39
37
|
end
|
40
|
-
|
41
|
-
def watch(
|
42
|
-
sleep(
|
43
|
-
|
38
|
+
|
39
|
+
def watch(application_group)
|
40
|
+
sleep(5)
|
41
|
+
|
44
42
|
loop do
|
45
|
-
applications.each
|
46
|
-
sleep(10)
|
47
|
-
|
43
|
+
application_group.applications.each do |a|
|
48
44
|
unless a.running?
|
49
45
|
a.zap!
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
46
|
+
|
47
|
+
sleep(1)
|
48
|
+
|
49
|
+
Process.detach(fork { a.start(restart = true) })
|
50
|
+
|
51
|
+
sleep(5)
|
52
|
+
|
53
|
+
# application_group.setup
|
54
54
|
end
|
55
|
-
|
56
|
-
|
57
|
-
sleep(
|
55
|
+
end
|
56
|
+
|
57
|
+
# sleep(5)
|
58
|
+
# application_group.setup
|
59
|
+
# sleep(30)
|
58
60
|
end
|
59
61
|
end
|
60
62
|
private :watch
|
61
|
-
|
62
|
-
|
63
|
-
def start_with_pidfile(applications)
|
63
|
+
|
64
|
+
def start_with_pidfile(application_group)
|
64
65
|
fork do
|
65
66
|
Daemonize.daemonize(nil, @app_name)
|
66
|
-
|
67
|
-
begin
|
67
|
+
|
68
|
+
begin
|
68
69
|
@pid.pid = Process.pid
|
69
|
-
|
70
|
+
|
70
71
|
# at_exit {
|
71
72
|
# begin; @pid.cleanup; rescue ::Exception; end
|
72
73
|
# }
|
73
|
-
|
74
|
-
# This part is needed to remove the pid-file if the application is killed by
|
74
|
+
|
75
|
+
# This part is needed to remove the pid-file if the application is killed by
|
75
76
|
# daemons or manually by the user.
|
76
77
|
# Note that the applications is not supposed to overwrite the signal handler for
|
77
78
|
# 'TERM'.
|
@@ -80,16 +81,16 @@ module Daemons
|
|
80
81
|
# begin; @pid.cleanup; rescue ::Exception; end
|
81
82
|
# exit
|
82
83
|
# }
|
83
|
-
|
84
|
-
watch(
|
84
|
+
|
85
|
+
watch(application_group)
|
85
86
|
rescue ::Exception => e
|
86
87
|
begin
|
87
|
-
File.open(@app.logfile, 'a')
|
88
|
+
File.open(@app.logfile, 'a') do |f|
|
88
89
|
f.puts Time.now
|
89
90
|
f.puts e
|
90
91
|
f.puts e.backtrace.inspect
|
91
|
-
|
92
|
-
ensure
|
92
|
+
end
|
93
|
+
ensure
|
93
94
|
begin; @pid.cleanup; rescue ::Exception; end
|
94
95
|
exit!
|
95
96
|
end
|
@@ -97,42 +98,39 @@ module Daemons
|
|
97
98
|
end
|
98
99
|
end
|
99
100
|
private :start_with_pidfile
|
100
|
-
|
101
|
-
def start_without_pidfile(
|
102
|
-
Thread.new { watch(
|
101
|
+
|
102
|
+
def start_without_pidfile(application_group)
|
103
|
+
Thread.new { watch(application_group) }
|
103
104
|
end
|
104
105
|
private :start_without_pidfile
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
106
|
+
|
107
|
+
def start(application_group)
|
108
|
+
return if application_group.applications.empty?
|
109
|
+
|
110
110
|
if @pid.kind_of?(PidFile)
|
111
|
-
start_with_pidfile(
|
111
|
+
start_with_pidfile(application_group)
|
112
112
|
else
|
113
|
-
start_without_pidfile(
|
113
|
+
start_without_pidfile(application_group)
|
114
114
|
end
|
115
115
|
end
|
116
|
-
|
117
|
-
|
116
|
+
|
118
117
|
def stop
|
119
118
|
begin
|
120
119
|
pid = @pid.pid
|
121
120
|
Process.kill(Application::SIGNAL, pid)
|
122
|
-
|
123
|
-
|
124
|
-
|
121
|
+
Timeout.timeout(5, TimeoutError) do
|
122
|
+
while Pid.running?(pid)
|
123
|
+
sleep(0.1)
|
124
|
+
end
|
125
125
|
end
|
126
|
-
}
|
127
126
|
rescue ::Exception => e
|
128
127
|
puts "#{e} #{pid}"
|
129
|
-
puts
|
128
|
+
puts 'deleting pid-file.'
|
130
129
|
end
|
131
|
-
|
130
|
+
|
132
131
|
# We try to remove the pid-files by ourselves, in case the application
|
133
132
|
# didn't clean it up.
|
134
133
|
begin; @pid.cleanup; rescue ::Exception; end
|
135
134
|
end
|
136
|
-
|
137
|
-
|
138
|
-
end
|
135
|
+
end
|
136
|
+
end
|