basic_daemon 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +94 -0
- data/examples/functional.rb +38 -0
- data/examples/objectoriented.rb +41 -0
- data/lib/basic_daemon.rb +187 -0
- data/test/basic_daemon_settings_test.rb +72 -0
- data/test/functional_basic_daemon_test.rb +76 -0
- data/test/oo_basic_daemon_test.rb +89 -0
- metadata +63 -0
data/README
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
A basic library for creating daemonized processes
|
2
|
+
(c) 2009 Samuel Mullen (samullen)
|
3
|
+
|
4
|
+
http://github.com/samullen/basic_daemon
|
5
|
+
|
6
|
+
This library works with Ruby 1.8, Ruby 1.9, and JRuby and is licensed under the MIT License.
|
7
|
+
|
8
|
+
Gettings Started
|
9
|
+
|
10
|
+
There are currently two ways of using the basic_daemon library: 1) Objected Oriented; 2) Functional.
|
11
|
+
|
12
|
+
Object Oriented
|
13
|
+
|
14
|
+
The basic idea here is to subclass BasicDaemon and overwrite the "run" method.
|
15
|
+
|
16
|
+
require 'basic_daemon'
|
17
|
+
|
18
|
+
class MyDaemon < BasicDaemon
|
19
|
+
def run
|
20
|
+
foo = open("/tmp/out", "w")
|
21
|
+
|
22
|
+
i = 1
|
23
|
+
|
24
|
+
while true do
|
25
|
+
foo.puts "loop: #{i}"
|
26
|
+
foo.flush
|
27
|
+
sleep 2
|
28
|
+
|
29
|
+
i += 1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
daemon = MyDaemon.new
|
35
|
+
|
36
|
+
if ARGV[0] == 'start'
|
37
|
+
daemon.start
|
38
|
+
elsif ARGV[0] == 'stop'
|
39
|
+
daemon.stop
|
40
|
+
exit!
|
41
|
+
elsif ARGV[0] == 'restart'
|
42
|
+
daemon.restart
|
43
|
+
else
|
44
|
+
STDERR.puts "Usage: foo_daemon.rb <start|stop|restart>"
|
45
|
+
exit!
|
46
|
+
end
|
47
|
+
|
48
|
+
Functional
|
49
|
+
|
50
|
+
Rather than subclassing BasicDaemon, a block is just passed to the start method.
|
51
|
+
|
52
|
+
require 'basic_daemon'
|
53
|
+
|
54
|
+
daemon = BasicDaemon.new
|
55
|
+
|
56
|
+
if ARGV[0] == 'start'
|
57
|
+
daemon.start do
|
58
|
+
foo = open("/tmp/out", "w")
|
59
|
+
|
60
|
+
i = 1
|
61
|
+
|
62
|
+
while true do
|
63
|
+
foo.puts "loop: #{i}"
|
64
|
+
foo.flush
|
65
|
+
sleep 2
|
66
|
+
|
67
|
+
i += 1
|
68
|
+
end
|
69
|
+
end
|
70
|
+
elsif ARGV[0] == 'stop'
|
71
|
+
daemon.stop
|
72
|
+
exit!
|
73
|
+
elsif ARGV[0] == 'restart'
|
74
|
+
daemon.restart
|
75
|
+
else
|
76
|
+
STDERR.puts "Usage: foo_daemon.rb <start|stop|restart>"
|
77
|
+
exit!
|
78
|
+
end
|
79
|
+
|
80
|
+
Arguments
|
81
|
+
|
82
|
+
BasicDaemon creates file to store the process ID (PID). By default, this file is given the same name as the calling script sans the file extension and is stored in the /tmp directory. Also by default, the directory the calling script is working in is changed to the root directory ('/').
|
83
|
+
|
84
|
+
Each argument, :pidfile, :piddir, :workingdir, can be changed upon instantiation of the class.
|
85
|
+
|
86
|
+
Example:
|
87
|
+
|
88
|
+
Most Linux users will want to instantiate thusly:
|
89
|
+
|
90
|
+
BasicDaemon.new(:piddir => '/var/lock')
|
91
|
+
|
92
|
+
Installation
|
93
|
+
|
94
|
+
pending
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# STDERR.puts "this won't work until I get the block stuff working."
|
4
|
+
# exit
|
5
|
+
|
6
|
+
require File.join(File.dirname(__FILE__), '..', 'lib','basic_daemon')
|
7
|
+
|
8
|
+
basedir = "/tmp" # change this to where you want to deal with things
|
9
|
+
pidfile = File.basename($PROGRAM_NAME, File.extname($PROGRAM_NAME))
|
10
|
+
|
11
|
+
d = BasicDaemon.new({:pidfile => pidfile, :piddir => basedir, :workingdir => basedir})
|
12
|
+
|
13
|
+
if ARGV[0] == 'start'
|
14
|
+
puts "should print 'got here' on the next line"
|
15
|
+
d.start do
|
16
|
+
i = 1
|
17
|
+
foo = open(basedir + "/out", "w")
|
18
|
+
|
19
|
+
while true do
|
20
|
+
foo.puts "loop: #{i}"
|
21
|
+
foo.flush
|
22
|
+
sleep 5
|
23
|
+
|
24
|
+
i += 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
elsif ARGV[0] == 'stop'
|
28
|
+
d.stop
|
29
|
+
exit!
|
30
|
+
elsif ARGV[0] == 'restart'
|
31
|
+
d.restart
|
32
|
+
else
|
33
|
+
STDERR.puts "wrong! use start or stop."
|
34
|
+
exit!
|
35
|
+
end
|
36
|
+
|
37
|
+
puts 'got here'
|
38
|
+
exit
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib','basic_daemon')
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
basedir = "/tmp" # change this to where you want to deal with things
|
7
|
+
pidfile = File.basename($PROGRAM_NAME, File.extname($PROGRAM_NAME))
|
8
|
+
|
9
|
+
class MyDaemon < BasicDaemon
|
10
|
+
def run
|
11
|
+
foo = open("/tmp/out", "w")
|
12
|
+
|
13
|
+
i = 1
|
14
|
+
|
15
|
+
while true do
|
16
|
+
foo.puts "loop: #{i}"
|
17
|
+
foo.flush
|
18
|
+
sleep 5
|
19
|
+
|
20
|
+
i += 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
d = MyDaemon.new(:pidfile => pidfile, :piddir => basedir, :workingdir => basedir)
|
26
|
+
|
27
|
+
if ARGV[0] == 'start'
|
28
|
+
puts "Should print 'got here' on the next line"
|
29
|
+
d.start
|
30
|
+
elsif ARGV[0] == 'stop'
|
31
|
+
d.stop
|
32
|
+
exit!
|
33
|
+
elsif ARGV[0] == 'restart'
|
34
|
+
d.restart
|
35
|
+
else
|
36
|
+
STDERR.puts "wrong! use start or stop."
|
37
|
+
exit!
|
38
|
+
end
|
39
|
+
|
40
|
+
puts 'got here'
|
41
|
+
exit
|
data/lib/basic_daemon.rb
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
class BasicDaemon
|
2
|
+
attr_accessor :workingdir, :pidfile, :piddir, :process
|
3
|
+
|
4
|
+
VERSION = '0.9.0'
|
5
|
+
|
6
|
+
DEFAULT_OPTIONS = {
|
7
|
+
:pidfile => File.basename($PROGRAM_NAME, File.extname($PROGRAM_NAME)),
|
8
|
+
:piddir => '/tmp',
|
9
|
+
:workingdir => '/'
|
10
|
+
}
|
11
|
+
|
12
|
+
# Instantiate a new BasicDaemon
|
13
|
+
#
|
14
|
+
# Takes an optional hash with the following symbol keys:
|
15
|
+
# - :piddir = Directory to store the PID file in. Default is /tmp
|
16
|
+
# - :pidfile = name of the file to store the PID in. default is the script
|
17
|
+
# name sans extension.
|
18
|
+
# - :workingdir = Directory to work from. Default is "/" and should probably
|
19
|
+
# be left as such.
|
20
|
+
def initialize(*args)
|
21
|
+
opts = {}
|
22
|
+
|
23
|
+
case
|
24
|
+
when args.length == 0 then
|
25
|
+
when args.length == 1 && args[0].class == Hash then
|
26
|
+
arg = args.shift
|
27
|
+
|
28
|
+
if arg.class == Hash
|
29
|
+
opts = arg
|
30
|
+
end
|
31
|
+
else
|
32
|
+
raise ArgumentError, "new() expects hash or hashref as argument"
|
33
|
+
end
|
34
|
+
|
35
|
+
opts = DEFAULT_OPTIONS.merge opts
|
36
|
+
|
37
|
+
@piddir = opts[:piddir]
|
38
|
+
@pidfile = opts[:pidfile]
|
39
|
+
@workingdir = opts[:workingdir]
|
40
|
+
@pid = nil
|
41
|
+
@process = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the fullpath to the file containing the process ID (PID)
|
45
|
+
def pidpath
|
46
|
+
File.join(@piddir, @pidfile)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns the PID of the currently running daemon
|
50
|
+
def pid
|
51
|
+
return @pid unless @pid.nil?
|
52
|
+
|
53
|
+
begin
|
54
|
+
@pid = open(self.pidpath, 'r').read.to_i
|
55
|
+
rescue Errno::EACCES => e
|
56
|
+
STDERR.puts "Error: unable to open file #{self.pidpath} for reading:\n\t"+
|
57
|
+
"(#{e.class}) #{e.message}"
|
58
|
+
exit!
|
59
|
+
rescue => e
|
60
|
+
end
|
61
|
+
|
62
|
+
@pid
|
63
|
+
end
|
64
|
+
|
65
|
+
# Starts the daemon by forking the supplied process either by block or by
|
66
|
+
# overridden run method.
|
67
|
+
def start(&block)
|
68
|
+
if pid
|
69
|
+
STDERR.puts "pidfile #{self.pidpath} with pid #{@pid} already exists. " +
|
70
|
+
"Make sure this daemon is not already running."
|
71
|
+
exit!
|
72
|
+
end
|
73
|
+
|
74
|
+
if block_given?
|
75
|
+
@process = block
|
76
|
+
end
|
77
|
+
|
78
|
+
#----- Fork off from the calling process -----#
|
79
|
+
begin
|
80
|
+
fork do
|
81
|
+
Process.setsid #----- make forked process session leader
|
82
|
+
fork && exit!
|
83
|
+
|
84
|
+
at_exit do
|
85
|
+
delpidfile
|
86
|
+
end
|
87
|
+
|
88
|
+
Dir::chdir(@workingdir) #----- chdir to working directory
|
89
|
+
File::umask(0) #----- clear out file mode creation mask
|
90
|
+
|
91
|
+
begin
|
92
|
+
open(self.pidpath, "w") do |f|
|
93
|
+
@pid = Process.pid
|
94
|
+
f.puts @pid
|
95
|
+
end
|
96
|
+
rescue => e
|
97
|
+
STDERR.puts "Error: Unable to open #{self.pidpath} for writing:\n\t" +
|
98
|
+
"(#{e.class}) #{e.message}"
|
99
|
+
exit!
|
100
|
+
end
|
101
|
+
|
102
|
+
STDIN.reopen("/dev/null", 'r')
|
103
|
+
STDOUT.reopen("/dev/null", "w")
|
104
|
+
STDERR.reopen("/dev/null", "w")
|
105
|
+
|
106
|
+
unless @process.nil?
|
107
|
+
@process.call
|
108
|
+
else
|
109
|
+
self.run
|
110
|
+
end
|
111
|
+
end
|
112
|
+
rescue => e
|
113
|
+
STDERR.puts "Error: Failed to fork properly: \n\t: " +
|
114
|
+
"(#{e.class}) #{e.message}"
|
115
|
+
exit!
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# stops the daemon. It does this by retrieving the process ID (PID) of the
|
120
|
+
# currently running process from the pidfile and killing it till it's dead.
|
121
|
+
def stop
|
122
|
+
unless self.pid
|
123
|
+
STDERR.puts "pidfile #{self.pidpath} does not exist. Daemon not running?\n"
|
124
|
+
return # not an error in a restart
|
125
|
+
end
|
126
|
+
|
127
|
+
begin
|
128
|
+
while true do
|
129
|
+
Process.kill("TERM", self.pid)
|
130
|
+
sleep(0.1)
|
131
|
+
end
|
132
|
+
rescue Errno::ESRCH # gets here when there is no longer a process to kill
|
133
|
+
rescue => e
|
134
|
+
STDERR.puts "unable to terminate process: (#{e.class}) #{e.message}"
|
135
|
+
exit!
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# restarts the daemon by first killing it and then restarting.
|
140
|
+
#
|
141
|
+
# Warning: does not work if block is initially passed to start.
|
142
|
+
def restart
|
143
|
+
self.stop
|
144
|
+
@pid = nil
|
145
|
+
|
146
|
+
unless @process.nil?
|
147
|
+
self.start
|
148
|
+
else
|
149
|
+
self.start &@process
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Boolean. Does the current process exist? True or false.
|
154
|
+
# Reads the PID from the pidfile and attempts to "kill 0" the process.
|
155
|
+
# Success results in true; failure, false.
|
156
|
+
def process_exists?
|
157
|
+
begin
|
158
|
+
Process.kill(0, self.pid)
|
159
|
+
true
|
160
|
+
rescue Errno::ESRCH, TypeError # "PID is NOT running or is zombied
|
161
|
+
false
|
162
|
+
rescue Errno::EPERM
|
163
|
+
STDERR.puts "No permission to query #{pid}!";
|
164
|
+
rescue => e
|
165
|
+
STDERR.puts "(#{e.class}) #{e.message}:\n\t" <<
|
166
|
+
"Unable to determine status for #{pid}."
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# run should be overridden if using BasicDaemon Object Orientedly.
|
171
|
+
# See examples.
|
172
|
+
def run
|
173
|
+
end
|
174
|
+
|
175
|
+
private
|
176
|
+
|
177
|
+
#----------------------------------------------------------------------------#
|
178
|
+
def delpidfile
|
179
|
+
begin
|
180
|
+
File.unlink(self.pidpath)
|
181
|
+
rescue => e
|
182
|
+
STDERR.puts "ERROR: Unable to unlink #{self.pidpath}:\n\t" +
|
183
|
+
"(#{e.class}) #{e.message}"
|
184
|
+
exit
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib','basic_daemon')
|
4
|
+
|
5
|
+
class TestBasicDaemon < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@daemon = BasicDaemon.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_should_default_pidfile_to_program_name
|
11
|
+
file_sans_ext = File.basename($PROGRAM_NAME, File.extname($PROGRAM_NAME))
|
12
|
+
message = "#{@daemon.pidfile} and #{file_sans_ext} are not equal"
|
13
|
+
|
14
|
+
assert_equal @daemon.pidfile, file_sans_ext, message
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_should_default_piddir_to_tmp
|
18
|
+
message = "PID Directory #{@daemon.piddir} should default to '/tmp'"
|
19
|
+
|
20
|
+
assert_equal @daemon.piddir, "/tmp", message
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_should_default_working_directory_to_root
|
24
|
+
message = "Working Directory #{@daemon.workingdir} should default to '/'"
|
25
|
+
|
26
|
+
assert_equal @daemon.workingdir, "/", message
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_update_of_pidfile
|
30
|
+
message = "PID File should be set to 'foo.txt'"
|
31
|
+
new_pidfile = 'foo.txt'
|
32
|
+
|
33
|
+
@daemon.pidfile = new_pidfile
|
34
|
+
assert_equal @daemon.pidfile, new_pidfile, message
|
35
|
+
assert_equal @daemon.pidpath, "/tmp/#{new_pidfile}", message
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_pid_method_should_return_nil
|
39
|
+
assert_nil @daemon.pid
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class TestWithSuppliedValues < Test::Unit::TestCase
|
44
|
+
def setup
|
45
|
+
@daemon = BasicDaemon.new({:pidfile => 'foo', :piddir => '/var/lock', :workingdir => '/var/lock'})
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_should_default_pidfile_to_foo
|
49
|
+
message = "#{@daemon.pidfile} and 'foo' are not equal"
|
50
|
+
|
51
|
+
assert_equal @daemon.pidfile, "foo", message
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_should_default_piddir_to_varlock
|
55
|
+
message = "PID Directory #{@daemon.piddir} should default to '/var/lock'"
|
56
|
+
|
57
|
+
assert_equal @daemon.piddir, "/var/lock", message
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_should_default_piddir_to_varlockfoo
|
61
|
+
message = "PID Path #{@daemon.pidpath} should default to '/var/lock/foo'"
|
62
|
+
|
63
|
+
assert_equal @daemon.pidpath, "/var/lock/foo", message
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_should_default_working_directory_to_varlock
|
67
|
+
message = "Working Directory #{@daemon.workingdir} should default to '/var/lock'"
|
68
|
+
|
69
|
+
assert_equal @daemon.workingdir, "/var/lock", message
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib','basic_daemon')
|
4
|
+
|
5
|
+
class TestFunctionalBasicDaemon < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@daemon = BasicDaemon.new
|
8
|
+
|
9
|
+
@process = Proc.new do
|
10
|
+
foo = open("/tmp/out", "w")
|
11
|
+
|
12
|
+
i = 1
|
13
|
+
|
14
|
+
while true do
|
15
|
+
foo.puts "loop: #{i}"
|
16
|
+
foo.flush
|
17
|
+
sleep 2
|
18
|
+
|
19
|
+
i += 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def teardown
|
25
|
+
@daemon.process_exists? && @daemon.stop
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_creation_deletion_of_pidfile
|
29
|
+
@daemon.start &@process
|
30
|
+
|
31
|
+
sleep 0.1 #----- give child proc time to create file
|
32
|
+
assert File.exists?(@daemon.pidpath), "PID file at #{@daemon.pidpath} should exist"
|
33
|
+
assert_match(/^\d+$/, File.open(@daemon.pidpath, 'r').read, "PID should be numeric")
|
34
|
+
|
35
|
+
@daemon.stop
|
36
|
+
assert File.exists?(@daemon.pidpath) == false, "PID file at #{@daemon.pidpath} should not exist"
|
37
|
+
assert @daemon.process_exists? == false, "Process should not exist"
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_pidfile_removal_upon_termination
|
41
|
+
@daemon.start &@process
|
42
|
+
sleep 0.1 #----- give child proc time to create file
|
43
|
+
pid = File.open(@daemon.pidpath, 'r').read.to_i
|
44
|
+
|
45
|
+
begin
|
46
|
+
while true do
|
47
|
+
Process.kill("TERM", pid)
|
48
|
+
sleep(0.1)
|
49
|
+
end
|
50
|
+
rescue Errno::ESRCH
|
51
|
+
end
|
52
|
+
assert @daemon.process_exists? == false
|
53
|
+
|
54
|
+
assert File.exists?(@daemon.pidpath) == false
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_backgrounding_of_subclassed_daemon
|
58
|
+
@daemon.start &@process
|
59
|
+
sleep 0.1 #----- give child proc time to create file
|
60
|
+
assert @daemon.process_exists?
|
61
|
+
@daemon.stop
|
62
|
+
assert @daemon.process_exists? == false
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_restart
|
66
|
+
@daemon.start &@process
|
67
|
+
sleep 0.1
|
68
|
+
assert @daemon.process_exists?
|
69
|
+
previous_pid = @daemon.pid
|
70
|
+
|
71
|
+
@daemon.restart
|
72
|
+
sleep 0.1
|
73
|
+
assert @daemon.process_exists?
|
74
|
+
assert previous_pid != @daemon.pid
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib','basic_daemon')
|
4
|
+
|
5
|
+
#------------------------------------------------------------------------------#
|
6
|
+
# OO Testing
|
7
|
+
#------------------------------------------------------------------------------#
|
8
|
+
|
9
|
+
#----- Really needs to be in a helper file -----#
|
10
|
+
class MyDaemon < BasicDaemon
|
11
|
+
def run
|
12
|
+
foo = open("/tmp/out", "w")
|
13
|
+
|
14
|
+
i = 1
|
15
|
+
|
16
|
+
while true do
|
17
|
+
foo.puts "loop: #{i}"
|
18
|
+
foo.flush
|
19
|
+
sleep 2
|
20
|
+
|
21
|
+
i += 1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class TestSubclassedBasicDaemon < Test::Unit::TestCase
|
27
|
+
def setup
|
28
|
+
@mydaemon = MyDaemon.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def teardown
|
32
|
+
@mydaemon.process_exists? && @mydaemon.stop
|
33
|
+
end
|
34
|
+
|
35
|
+
#------------------------------------------------------------------------------#
|
36
|
+
def test_creation_deletion_of_pidfile
|
37
|
+
assert_nil @mydaemon.pid, "pidfile shouldn't exist so pid should be nil."
|
38
|
+
|
39
|
+
@mydaemon.start
|
40
|
+
sleep 0.1 #----- give child proc time to create file
|
41
|
+
|
42
|
+
assert File.exists?(@mydaemon.pidpath), "PID file at #{@mydaemon.pidpath} should exist"
|
43
|
+
assert_match(/^\d+$/, File.open(@mydaemon.pidpath, 'r').read, "PID should be numeric")
|
44
|
+
|
45
|
+
@mydaemon.stop
|
46
|
+
assert File.exists?(@mydaemon.pidpath) == false, "PID file at #{@mydaemon.pidpath} should no longer exist"
|
47
|
+
assert @mydaemon.process_exists? == false, "Process should no longer exist."
|
48
|
+
end
|
49
|
+
|
50
|
+
#------------------------------------------------------------------------------#
|
51
|
+
def test_pidfile_removal_upon_termination
|
52
|
+
@mydaemon.start
|
53
|
+
sleep 0.1 #----- give child proc time to create file
|
54
|
+
|
55
|
+
begin
|
56
|
+
while true do
|
57
|
+
Process.kill("TERM", @mydaemon.pid)
|
58
|
+
sleep(0.1)
|
59
|
+
end
|
60
|
+
rescue Errno::ESRCH
|
61
|
+
end
|
62
|
+
|
63
|
+
assert @mydaemon.process_exists? == false, "External termination of the process should register with the daemon."
|
64
|
+
assert File.exists?(@mydaemon.pidpath) == false, "pidfile should be deleted when the process is terminated externally"
|
65
|
+
end
|
66
|
+
|
67
|
+
#------------------------------------------------------------------------------#
|
68
|
+
def test_backgrounding_of_subclassed_daemon
|
69
|
+
@mydaemon.start
|
70
|
+
sleep 0.1 #----- give child proc time to create file
|
71
|
+
assert @mydaemon.process_exists?
|
72
|
+
@mydaemon.stop
|
73
|
+
assert @mydaemon.process_exists? == false
|
74
|
+
end
|
75
|
+
|
76
|
+
#------------------------------------------------------------------------------#
|
77
|
+
def test_restart
|
78
|
+
@mydaemon.start
|
79
|
+
sleep 0.1
|
80
|
+
assert @mydaemon.process_exists?
|
81
|
+
previous_pid = @mydaemon.pid
|
82
|
+
|
83
|
+
@mydaemon.restart
|
84
|
+
sleep 0.1
|
85
|
+
assert @mydaemon.process_exists?
|
86
|
+
assert previous_pid != @mydaemon.pid
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: basic_daemon
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Samuel Mullen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-18 00:00:00 -06:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: "false"
|
17
|
+
email: samullen@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
- examples/functional.rb
|
27
|
+
- examples/objectoriented.rb
|
28
|
+
- lib/basic_daemon.rb
|
29
|
+
- test/oo_basic_daemon_test.rb
|
30
|
+
- test/basic_daemon_settings_test.rb
|
31
|
+
- test/functional_basic_daemon_test.rb
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: http://github.com/samullen/basic_daemon
|
34
|
+
licenses: []
|
35
|
+
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.3.5
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: A simple ruby library for daemonizing processes
|
60
|
+
test_files:
|
61
|
+
- test/oo_basic_daemon_test.rb
|
62
|
+
- test/basic_daemon_settings_test.rb
|
63
|
+
- test/functional_basic_daemon_test.rb
|