FooBarWidget-daemon_controller 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.markdown CHANGED
@@ -24,7 +24,7 @@ some of them.
24
24
  ### Starting daemons is a hassle
25
25
 
26
26
  If you've used similar software, then you might agree that managing these
27
- daemons are a hassle. If you're using BackgrounDRb, then the daemon must be
27
+ daemons is a hassle. If you're using BackgrounDRb, then the daemon must be
28
28
  running. Starting the daemon is not hard, but it is annoying. It's also
29
29
  possible that the system administrator forgets to start the daemon. While
30
30
  configuring the system to automatically start a daemon at startup is not hard,
@@ -209,6 +209,46 @@ daemon_controller's goal is to make daemon management less of a hassle, and as
209
209
  automatic and straightforward as possible.
210
210
 
211
211
 
212
+ What about Monit/God?
213
+ =====================
214
+
215
+ daemon_controller is not a replacement for [Monit](http://www.tildeslash.com/monit/)
216
+ or [God](http://god.rubyforge.org/). Rather, it is a solution to the following
217
+ problem:
218
+
219
+ > **Hongli:** hey Ninh, do a 'git pull', I just implemented awesome searching
220
+ > features in our application!
221
+ > **Ninh:** cool. *pulls from repository*
222
+ > **Ninh:** hey Hongli, it doesn't work.
223
+ > **Hongli:** what do you mean, it doesn't work?
224
+ > **Ninh:** it says "connection refused", or something
225
+ > **Hongli:** oh I forgot to mention it, you have to run the Sphinx search
226
+ > daemon before it works. type "rake sphinx:daemon:start" to do
227
+ > that
228
+ > **Ninh:** great. but now I get a different error. something about
229
+ > BackgrounDRb.
230
+ > **Hongli:** oops, I forgot to mention this too. you need to start the
231
+ > BackgrounDRb server with "rake backgroundrb:start_server"
232
+ > **Ninh:** okay, so every time I want to use this app, I have to type
233
+ > "rake sphinx:daemon:start", "rake backgroundrb:start_server" and
234
+ > "./script/server"?
235
+ > **Hongli:** yep
236
+
237
+ Imagine the above conversation becoming just:
238
+
239
+ > **Hongli:** hey Ninh, do a 'git pull', I just implemented awesome searching
240
+ > features in our application!
241
+ > **Ninh:** cool. *pulls from repository*
242
+ > **Ninh:** awesome, it works!
243
+
244
+ This is not something that can be achieved with Monit/God. Monit/God are for
245
+ monitoring daemons, auto-restarting them when they use too much resources.
246
+ daemon_controller's goal is to allow developers to implement daemon
247
+ starting/stopping and daemon auto-starting code that's robust. daemon_controller
248
+ is intended to be used to make daemon-dependent applications Just Work(tm)
249
+ without having to start the daemons manually.
250
+
251
+
212
252
  Tutorial #1: controlling Apache
213
253
  ===============================
214
254
 
@@ -271,7 +311,7 @@ raises `Errno::ECONNREFUSED`, then that's also interpreted by DaemonController
271
311
  as meaning that the daemon isn't responding yet.
272
312
 
273
313
  After `controller.start` has returned, we can continue with the test case. At
274
- this point, we know that Apache has done initializing.
314
+ this point, we know that Apache is done with initializing.
275
315
  When we're done with Apache, we stop it with `controller.stop`. This does not
276
316
  return until Apache has fully stopped.
277
317
 
@@ -295,7 +335,7 @@ that there's little room for human screw-up, and so we've developed this
295
335
  library. Our Sphinx search daemon is completely managed through this library
296
336
  and is automatically started on demand.
297
337
 
298
- Our Sphinx config file is generated from an ERB template. This ERB templates
338
+ Our Sphinx config file is generated from an ERB template. This ERB template
299
339
  writes different values in the config file, depending on whether we're in
300
340
  development, test or production mode. We will want to regenerate this config
301
341
  file every time, just before we start the search daemon.
@@ -325,7 +365,7 @@ This can be achieved with the following code:
325
365
  :before_start => method(:before_start),
326
366
  :ping_command => lambda { TCPSocket.new('localhost', SEARCH_SERVER_PORT) },
327
367
  :pid_file => 'tmp/pids/sphinx.pid',
328
- :log_file => 'log/sphinx.log',
368
+ :log_file => 'log/sphinx.log')
329
369
  end
330
370
 
331
371
  def query(search_terms)
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "daemon_controller"
3
- s.version = "0.2.0"
4
- s.date = "2008-08-21"
3
+ s.version = "0.2.1"
4
+ s.date = "2009-02-22"
5
5
  s.summary = "A library for implementing daemon management capabilities"
6
6
  s.email = "hongli@phusion.nl"
7
7
  s.homepage = "http://github.com/FooBarWidget/daemon_controller/tree/master"
@@ -21,12 +21,13 @@
21
21
 
22
22
  require 'tempfile'
23
23
  require 'fcntl'
24
+ require 'timeout'
24
25
  require File.expand_path(File.dirname(__FILE__) << '/daemon_controller/lock_file')
25
26
 
26
27
  # Main daemon controller object. See the README for an introduction and tutorial.
27
28
  class DaemonController
28
29
  ALLOWED_CONNECT_EXCEPTIONS = [Errno::ECONNREFUSED, Errno::ENETUNREACH,
29
- Errno::ETIMEDOUT, Errno::ECONNRESET]
30
+ Errno::ETIMEDOUT, Errno::ECONNRESET, Errno::EINVAL]
30
31
 
31
32
  class Error < StandardError
32
33
  end
@@ -497,6 +498,11 @@ private
497
498
  STDIN.reopen("/dev/null", "r")
498
499
  STDOUT.reopen(tempfile_path, "w")
499
500
  STDERR.reopen(tempfile_path, "w")
501
+ ObjectSpace.each_object(IO) do |obj|
502
+ if STDIN != obj && STDOUT != obj && STDERR != obj
503
+ obj.close rescue nil
504
+ end
505
+ end
500
506
  exec(command)
501
507
  end
502
508
  begin
@@ -519,7 +525,9 @@ private
519
525
  raise StartError, File.read(tempfile_path).strip
520
526
  end
521
527
  else
522
- if !system("#{command} >\"#{tempfile_path}\" 2>\"#{tempfile_path}\"")
528
+ cmd = "#{command} >\"#{tempfile_path}\""
529
+ cmd += " 2>\"#{tempfile_path}\"" unless PLATFORM =~ /mswin/
530
+ if !system(cmd)
523
531
  raise StartError, File.read(tempfile_path).strip
524
532
  end
525
533
  end
@@ -21,6 +21,9 @@
21
21
 
22
22
  class DaemonController
23
23
  class LockFile
24
+ class AlreadyLocked < StandardError
25
+ end
26
+
24
27
  def initialize(filename)
25
28
  @filename = filename
26
29
  end
@@ -44,5 +47,31 @@ class LockFile
44
47
  yield
45
48
  end
46
49
  end
47
- end # class PidFile
50
+
51
+ def try_shared_lock
52
+ File.open(@filename, 'w') do |f|
53
+ if Fcntl.const_defined? :F_SETFD
54
+ f.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
55
+ end
56
+ if f.flock(File::LOCK_SH | File::LOCK_NB)
57
+ yield
58
+ else
59
+ raise AlreadyLocked
60
+ end
61
+ end
62
+ end
63
+
64
+ def try_exclusive_lock
65
+ File.open(@filename, 'w') do |f|
66
+ if Fcntl.const_defined? :F_SETFD
67
+ f.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
68
+ end
69
+ if f.flock(File::LOCK_EX | File::LOCK_NB)
70
+ yield
71
+ else
72
+ raise AlreadyLocked
73
+ end
74
+ end
75
+ end
76
+ end # class LockFile
48
77
  end # class DaemonController
@@ -165,8 +165,12 @@ describe DaemonController, "#start" do
165
165
  @controller.should_receive(:start_timed_out).and_return do
166
166
  end_time = Time.now
167
167
  end
168
- lambda { @controller.start }.should raise_error(DaemonController::StartTimeout)
169
- (min_start_timeout .. max_start_timeout).should === end_time - start_time
168
+ begin
169
+ lambda { @controller.start }.should raise_error(DaemonController::StartTimeout)
170
+ (min_start_timeout .. max_start_timeout).should === end_time - start_time
171
+ ensure
172
+ @controller.stop
173
+ end
170
174
  end
171
175
 
172
176
  it "kills the daemon with a signal if the daemon doesn't start in time and there's a PID file" do
@@ -178,7 +182,14 @@ describe DaemonController, "#start" do
178
182
  end
179
183
  pid = @controller.send(:read_pid_file)
180
184
  end
181
- lambda { @controller.start }.should raise_error(DaemonController::StartTimeout)
185
+ begin
186
+ lambda { @controller.start }.should raise_error(DaemonController::StartTimeout)
187
+ ensure
188
+ # It's possible that because of a racing condition, the PID
189
+ # file doesn't get deleted before the next test is run. So
190
+ # here we ensure that the PID file is gone.
191
+ File.unlink("echo_server.pid") rescue nil
192
+ end
182
193
  end
183
194
 
184
195
  if DaemonController.send(:fork_supported?)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: FooBarWidget-daemon_controller
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hongli Lai
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-08-21 00:00:00 -07:00
12
+ date: 2009-02-22 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15