servolux 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,4 +1,10 @@
1
- == 0.4.0 / 2009-07-01
1
+ == 0.5.0 / 2009-06-30
2
+
3
+ * 2 Minor Enchancements
4
+ * Added tests for the Child class
5
+ * Updating documentation in preperation for a release
6
+
7
+ == 0.4.0 / 2009-06-29
2
8
 
3
9
  * 1 Minor Enhancement
4
10
  * Added a "Child" class for working with child processes
data/README.rdoc CHANGED
@@ -4,18 +4,39 @@
4
4
 
5
5
  === DESCRIPTION:
6
6
 
7
- Threads : Servers : Forks : Daemons : Serv-O-Lux has them all!
7
+ Serv-O-Lux is a collection of Ruby classes that are useful for daemon and
8
+ process management, and for writing your own Ruby services. The code is well
9
+ documented and tested. It works with Ruby and JRuby supporing both 1.8 and 1.9
10
+ interpreters.
8
11
 
9
12
  === FEATURES:
10
13
 
11
- http://codeforpeople.rubyforge.org/servolux
14
+ Servolux::Threaded -- when included into your own class, it gives you an
15
+ activity thread that will run some code at a regular interval. Provides methods
16
+ to start and stop the thread, report on the running state, and join the thread
17
+ to wait for it to complete.
12
18
 
13
- === SYNOPSIS:
19
+ Servolux::Server -- a template server class that handles the mundane work of
20
+ creating / deleting a PID file, reporting running state, logging errors,
21
+ starting the service, and gracefully shutting down the service.
14
22
 
23
+ Servolux::Piper -- an extension of the standard Ruby fork method that opens a
24
+ pipe for communication between parent and child processes. Ruby objects are
25
+ passed between parent and child allowing, for example, exceptions in the child
26
+ process to be passed to the parent and raised there.
27
+
28
+ Servolux::Daemon -- a robust class for starting and stopping daemon processes.
29
+
30
+ Servolux::Child -- adds some much needed funtionality to child processes
31
+ created via Ruby's IO#popen method. Specifically, a timeout thread is used to
32
+ signal the child process to die if it does not exit in a given amount of time.
33
+
34
+
35
+ All the documentation is available online at http://codeforpeople.rubyforge.org/servolux
15
36
 
16
37
  === INSTALL:
17
38
 
18
- gem install servolux
39
+ gem install servolux
19
40
 
20
41
  === LICENSE:
21
42
 
data/lib/servolux.rb CHANGED
@@ -4,7 +4,7 @@ require 'logging'
4
4
  module Servolux
5
5
 
6
6
  # :stopdoc:
7
- VERSION = '0.4.0'
7
+ VERSION = '0.5.0'
8
8
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
9
9
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
10
10
  # :startdoc:
@@ -1,5 +1,41 @@
1
1
 
2
+ # == Synopsis
3
+ # Manage a child process spawned via IO#popen and provide a timeout
4
+ # mechanism to kill the process after some amount time.
2
5
  #
6
+ # == Details
7
+ # Ruby provides the IO#popen method to spawn a child process and return an
8
+ # IO instance connected to the child's stdin and stdout (with stderr
9
+ # redirected to stdout). The Servolux::Child class adds to this a timeout
10
+ # thread that will signal the child process after some number of seconds.
11
+ # If the child exits cleanly before the timeout expires then no signals are
12
+ # sent to the child.
13
+ #
14
+ # A list of signals can be provided which will be sent in succession to the
15
+ # child until one of them causes the child to exit. The current Ruby thread
16
+ # suspends for a few seconds to allow each signal to be processed by the
17
+ # child. By default these signals are SIGTERM, SIGQUIT, SIGKILL and the time
18
+ # to wait between signals is four seconds.
19
+ #
20
+ # The +stop+ method is used to stop the child process (if running) and to
21
+ # reset the state of the Child instance so that it can be started again.
22
+ # Stopping the Child instance closes the IO between parent and child
23
+ # process.
24
+ #
25
+ # The +wait+ method is used to wait for the child process to exit. The
26
+ # Process::Status object is retrieved by the Child and stored as an instance
27
+ # variable. The +exitstatus+ method (and the other process related methods)
28
+ # will return non-nil values after the wait method is called.
29
+ #
30
+ # == Examples
31
+ #
32
+ # child = Servolux::Child.new(:command => 'sleep 120', :timeout => 10)
33
+ # child.start
34
+ # child.wait
35
+ #
36
+ # child.timed_out? #=> true
37
+ # child.signaled? #=> true
38
+ # child.exitstatus #=> nil
3
39
  #
4
40
  class Servolux::Child
5
41
 
@@ -10,29 +46,63 @@ class Servolux::Child
10
46
  attr_reader :io
11
47
  attr_reader :pid
12
48
 
49
+ # Create a new Child that will execute and manage the +command+ string as
50
+ # a child process.
51
+ #
52
+ # ==== Options
53
+ # * command <String>
54
+ # The command that will be executed via IO#popen.
13
55
  #
56
+ # * timeout <Numeric>
57
+ # The number of seconds to wait before terminating the child process.
58
+ # No action is taken if the child process exits normally before the
59
+ # timeout expires.
14
60
  #
15
- def initialize( command, opts = {} )
16
- @command = command
61
+ # * signals <Array>
62
+ # A list of signals that will be sent to the child process when the
63
+ # timeout expires. The signals increase in severity with SIGKILL being
64
+ # the signal of last resort.
65
+ #
66
+ # * suspend <Numeric>
67
+ # The number of seconds to wait for the child process to respond to
68
+ # a signal before trying the next one in the list.
69
+ #
70
+ def initialize( opts = {} )
71
+ @command = opts.getopt :command
17
72
  @timeout = opts.getopt :timeout
18
73
  @signals = opts.getopt :signals, %w[TERM QUIT KILL]
19
74
  @suspend = opts.getopt :suspend, 4
20
- @io = @pid = @thread = @timed_out = nil
75
+ @io = @pid = @status = @thread = @timed_out = nil
76
+ yield self if block_given?
21
77
  end
22
78
 
79
+ # Runs the +command+ string as a subprocess; the subprocess’s
80
+ # standard input and output will be connected to the returned IO object.
81
+ # The default mode for the new file object is "r", but mode may be set to
82
+ # any of the modes listed in the description for class IO.
23
83
  #
84
+ # If a block is given, Ruby will run the +command+ as a child connected to
85
+ # Ruby with a pipe. Ruby’s end of the pipe will be passed as a parameter
86
+ # to the block. In this case the value of the block is returned.
24
87
  #
25
88
  def start( mode = 'r', &block )
26
89
  start_timeout_thread if @timeout
27
90
 
28
- @io = IO::popen @command, mode
91
+ @io = IO::popen @command, mode
29
92
  @pid = @io.pid
93
+ @status = nil
30
94
 
31
95
  return block.call(@io) unless block.nil?
32
- self
96
+ @io
33
97
  end
34
98
 
99
+ # Stop the child process if it is alive. A sequence of +signals+ are sent
100
+ # to the process until it dies with SIGKILL being the signal of last
101
+ # resort.
35
102
  #
103
+ # After this method returns, the IO pipe to the child will be closed and
104
+ # the stored child PID is set to +nil+. The +start+ method can be safely
105
+ # called again.
36
106
  #
37
107
  def stop
38
108
  unless @thread.nil?
@@ -43,7 +113,7 @@ class Servolux::Child
43
113
 
44
114
  kill if alive?
45
115
  @io.close rescue nil
46
- @io = @pid = nil
116
+ @io = nil
47
117
  self
48
118
  end
49
119
 
@@ -54,10 +124,12 @@ class Servolux::Child
54
124
  def wait( flags = 0 )
55
125
  return if @io.nil?
56
126
  Process.wait(@pid, flags)
57
- $?.exitstatus
127
+ @status = $?
128
+ exitstatus
58
129
  end
59
130
 
60
- # Returns +true+ if the child process is alive.
131
+ # Returns +true+ if the child process is alive. Returns +nil+ if the child
132
+ # process has not been started.
61
133
  #
62
134
  def alive?
63
135
  return if @io.nil?
@@ -73,10 +145,26 @@ class Servolux::Child
73
145
  @timed_out
74
146
  end
75
147
 
148
+ %w[coredump? exited? signaled? stopped? success? exitstatus stopsig termsig].
149
+ each { |method|
150
+ self.class_eval <<-CODE
151
+ def #{method}
152
+ return if @status.nil?
153
+ @status.#{method}
154
+ end
155
+ CODE
156
+ }
157
+
76
158
 
77
159
  private
78
160
 
161
+ # Attempt to kill the child process by sending the configured +signals+
162
+ # and waiting for +suspend+ seconds between each signal; this gives the
163
+ # child time to respond to the signal.
79
164
  #
165
+ # Returns +true+ if the child died. Returns +false+ if the child is still
166
+ # not dead after the last signal was sent. Returns +nil+ if the child was
167
+ # not running in the first place.
80
168
  #
81
169
  def kill
82
170
  return if @io.nil?
@@ -96,8 +184,6 @@ class Servolux::Child
96
184
  return !alive?
97
185
  end
98
186
 
99
- #
100
- #
101
187
  def start_timeout_thread
102
188
  @timed_out = false
103
189
  @thread = Thread.new(self) { |child|
@@ -1,3 +1,4 @@
1
+
1
2
  # == Synopsis
2
3
  # The Daemon takes care of the work of creating and managing daemon
3
4
  # processes from Ruby.
@@ -0,0 +1,51 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
3
+
4
+ describe Servolux::Child do
5
+
6
+ before :all do
7
+ @child = Servolux::Child.new
8
+ end
9
+
10
+ after :each do
11
+ @child.stop
12
+ end
13
+
14
+ it 'has some sensible defaults' do
15
+ @child.command.should be_nil
16
+ @child.timeout.should be_nil
17
+ @child.signals.should == %w[TERM QUIT KILL]
18
+ @child.suspend.should == 4
19
+ @child.pid.should be_nil
20
+ @child.io.should be_nil
21
+ end
22
+
23
+ it 'starts a child process' do
24
+ @child.command = 'echo `pwd`'
25
+ @child.start
26
+
27
+ @child.pid.should_not be_nil
28
+ @child.wait
29
+ @child.io.read.strip.should == Dir.pwd
30
+ @child.success?.should be_true
31
+ end
32
+
33
+ it 'kills a child process after some timeout' do
34
+ @child.command = 'sleep 5; echo `pwd`'
35
+ @child.timeout = 0.25
36
+ @child.start
37
+
38
+ @child.pid.should_not be_nil
39
+ @child.wait
40
+
41
+ @child.io.read.strip.should be_empty
42
+
43
+ @child.signaled?.should be_true
44
+ @child.exited?.should be_false
45
+ @child.exitstatus.should be_nil
46
+ @child.success?.should be_nil
47
+ end
48
+
49
+ end
50
+
51
+ # EOF
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: servolux
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Pease
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-29 00:00:00 -06:00
12
+ date: 2009-06-30 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -42,7 +42,7 @@ dependencies:
42
42
  - !ruby/object:Gem::Version
43
43
  version: 2.5.0
44
44
  version:
45
- description: "Threads : Servers : Forks : Daemons : Serv-O-Lux has them all!"
45
+ description: Serv-O-Lux is a collection of Ruby classes that are useful for daemon and process management, and for writing your own Ruby services. The code is well documented and tested. It works with Ruby and JRuby supporing both 1.8 and 1.9 interpreters.
46
46
  email: tim.pease@gmail.com
47
47
  executables: []
48
48
 
@@ -61,6 +61,7 @@ files:
61
61
  - lib/servolux/piper.rb
62
62
  - lib/servolux/server.rb
63
63
  - lib/servolux/threaded.rb
64
+ - spec/child_spec.rb
64
65
  - spec/piper_spec.rb
65
66
  - spec/server_spec.rb
66
67
  - spec/servolux_spec.rb
@@ -105,6 +106,6 @@ rubyforge_project: codeforpeople
105
106
  rubygems_version: 1.3.1
106
107
  signing_key:
107
108
  specification_version: 2
108
- summary: "Threads : Servers : Forks : Daemons : Serv-O-Lux has them all!"
109
+ summary: Serv-O-Lux is a collection of Ruby classes that are useful for daemon and process management, and for writing your own Ruby services
109
110
  test_files: []
110
111