process-daemon 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4f2719836b2dfefcb18754e6157764c3f964d667
4
- data.tar.gz: 696fd41006946dd13a6a04eaabef60e5f35c8925
3
+ metadata.gz: c61cccea3d2c60a71ac3a57248e041a6474d1fc8
4
+ data.tar.gz: 547c4355486f24c30eeb00c4aed3c633d0290656
5
5
  SHA512:
6
- metadata.gz: 4a2c171b1f7007a6c69e198ee47b56409c870a6c6fe525b6d0b75f75529ea8a4cc802bf22aaad27751f0ec7e631c6ea2221be4ad83e64b4ffe4fe84b1554aeb5
7
- data.tar.gz: 37b32a1adec863f0b34451b11e1dec6ddaed83e0c568be6f72d4171e5b878a7c873814353f19273ad901e63933381ee2a4699c340b18735742da40432bec4d2c
6
+ metadata.gz: c984adf509aa62ba982fccb52dea7f692b44b9300a38f79d4ce4c8225185e66b113ad723634aea8084a749cb8900ed3e3b30c567b381113dc1167e1adcc4af21
7
+ data.tar.gz: 195aff6013ab3a1b61d7865cf8292caafa05e797a1f01b9d8d4db8fdb4b0735d92d7f067217e70a0c79f2e194fcb9fe71b4959fafd84ba6d477f00867d16fe73
data/README.md CHANGED
@@ -32,11 +32,12 @@ A process daemon has a specific structure:
32
32
  end
33
33
 
34
34
  def run
35
- # Do the actual work. Does not need to be implemented, e.g. if using threads or other background processing mechanisms.
35
+ # Do the actual work. Does not need to be implemented, e.g. if using threads or other background processing mechanisms which were kicked off in #startup.
36
36
  end
37
37
 
38
38
  def shutdown
39
- # Stop everything that was setup in startup.
39
+ # Stop everything that was setup in startup. Called as part of main daemon thread/process, not in trap context (e.g. SIGINT).
40
+ # Asynchronous code can call self.request_shutdown from a trap context to interrupt the main process, provided you aren't doing work in #run.
40
41
  end
41
42
  end
42
43
 
@@ -57,6 +58,8 @@ After calling `prefork`, the working directory is expanded to a full path and sh
57
58
 
58
59
  ### WEBRick Server
59
60
 
61
+ Some servers must run on the main process thread. In this case, the normal interrupt mechanism won't be used and we will handle signals directly.
62
+
60
63
  Create a file for your daemon, e.g. `daemon.rb`:
61
64
 
62
65
  #!/usr/bin/env ruby
@@ -188,8 +188,12 @@ module Process
188
188
  end
189
189
 
190
190
  pgid = -Process.getpgid(pid)
191
-
191
+
192
+ # Stop by interrupt sends a single interrupt and waits for the process to terminate:
192
193
  unless stop_by_interrupt(pgid)
194
+ # If the process is still running, we try sending SIGTERM followed by SIGKILL:
195
+ @output.puts Rainbow("** Daemon did not stop gracefully after #{@stop_timeout}s **").red
196
+
193
197
  stop_by_terminate_or_kill(pgid)
194
198
  end
195
199
 
@@ -207,6 +211,7 @@ module Process
207
211
 
208
212
  private
209
213
 
214
+ # Returns true if the process was stopped.
210
215
  def stop_by_interrupt(pgid)
211
216
  running = true
212
217
 
@@ -219,7 +224,7 @@ module Process
219
224
  end
220
225
  end
221
226
 
222
- return running
227
+ return !running
223
228
  end
224
229
 
225
230
  def stop_by_terminate_or_kill(pgid)
@@ -0,0 +1,85 @@
1
+ # Copyright, 2016, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module Process
22
+ class Daemon
23
+ # Access incoming file descriptors from daemons started by systemd.
24
+ class Listen
25
+ LISTEN_PID = 'LISTEN_PID'
26
+ LISTEN_FDS = 'LISTEN_FDS'
27
+ LISTEN_FDNAMES = 'LISTEN_FDNAMES'
28
+
29
+ FD_START = 3
30
+ SEPERATOR = ':'
31
+
32
+ def self.set_close_at_exec(fd)
33
+ fd.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
34
+ end
35
+
36
+ def self.open(fd)
37
+ set_close_at_exec(fd)
38
+
39
+ return IO.for_fd(fd)
40
+ end
41
+
42
+ # Returns a Array or Hash of file descriptors. If LISTEN_FDNAMES is set, a Hash is returned which includes key => value pairs for named file descriptors.
43
+ def self.file_descriptors(env = ENV)
44
+ pid, fds, names = env.values_at(LISTEN_PID, LISTEN_FDS, LISTEN_FDNAMES)
45
+
46
+ # Are the PIDs valid for this process?
47
+ unless pid and Integer(pid) == Process.pid
48
+ return nil
49
+ end
50
+
51
+ files = Integer(fds).times.collect do |i|
52
+ self.open(FD_START + i)
53
+ end
54
+
55
+ if names
56
+ names = names.split(SEPARATOR, -1)
57
+ end
58
+
59
+ self.new(files, names)
60
+ end
61
+
62
+ def initialize(files, names)
63
+ @files = files
64
+ @names = names
65
+
66
+ @named = {}
67
+ @unnamed = []
68
+
69
+ @names.each_with_index do |name, index|
70
+ if name
71
+ @named[name] = @files[index]
72
+ else
73
+ @unnamed << @files[index]
74
+ end
75
+ end
76
+ end
77
+
78
+ attr :files
79
+ attr :names
80
+
81
+ attr :named
82
+ attr :unnamed
83
+ end
84
+ end
85
+ end
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Process
22
22
  class Daemon
23
- VERSION = "1.0.0"
23
+ VERSION = "1.0.1"
24
24
  end
25
25
  end
@@ -26,10 +26,6 @@ module Process::Daemon::ProcessFileSpec
26
26
  def working_directory
27
27
  File.expand_path("../tmp", __FILE__)
28
28
  end
29
-
30
- def startup
31
- sleep 1 while true
32
- end
33
29
  end
34
30
 
35
31
  describe Process::Daemon::ProcessFile do
@@ -0,0 +1,71 @@
1
+ # Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'process/daemon'
22
+ require 'process/daemon/process_file'
23
+
24
+ module Process::Daemon::TerminateSpec
25
+ class SleepDaemon < Process::Daemon
26
+ def working_directory
27
+ File.expand_path("../tmp", __FILE__)
28
+ end
29
+
30
+ def startup
31
+ setup_signals
32
+ end
33
+
34
+ def setup_signals
35
+ trap('INT') do
36
+ puts 'INT'
37
+ end
38
+
39
+ trap('TERM') do
40
+ puts 'TERM'
41
+ end
42
+ end
43
+
44
+ def run
45
+ sleep 1 while true
46
+ end
47
+ end
48
+
49
+ describe Process::Daemon do
50
+ let(:daemon) {SleepDaemon.instance}
51
+ let(:controller) {Process::Daemon::Controller.new(daemon)}
52
+
53
+ # Print out the daemon log file:
54
+ #after(:each) do
55
+ # system('cat', daemon.log_file_path)
56
+ #end
57
+
58
+ it "should be killed" do
59
+ controller.start
60
+
61
+ expect(controller.status).to be == :running
62
+
63
+ controller.stop
64
+
65
+ expect(controller.status).to be == :stopped
66
+
67
+ output = File.readlines(daemon.log_file_path).last(6)
68
+ expect(output).to be == ["INT\n", "TERM\n", "TERM\n", "TERM\n", "TERM\n", "TERM\n"]
69
+ end
70
+ end
71
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: process-daemon
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-03 00:00:00.000000000 Z
11
+ date: 2016-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rainbow
@@ -82,6 +82,7 @@ files:
82
82
  - Rakefile
83
83
  - lib/process/daemon.rb
84
84
  - lib/process/daemon/controller.rb
85
+ - lib/process/daemon/listen.rb
85
86
  - lib/process/daemon/log_file.rb
86
87
  - lib/process/daemon/notification.rb
87
88
  - lib/process/daemon/privileges.rb
@@ -96,6 +97,7 @@ files:
96
97
  - spec/process/daemon/notification_spec.rb
97
98
  - spec/process/daemon/privileges_spec.rb
98
99
  - spec/process/daemon/process_file_spec.rb
100
+ - spec/process/daemon/terminate_spec.rb
99
101
  homepage: https://github.com/ioquatix/process-daemon
100
102
  licenses:
101
103
  - MIT
@@ -130,3 +132,4 @@ test_files:
130
132
  - spec/process/daemon/notification_spec.rb
131
133
  - spec/process/daemon/privileges_spec.rb
132
134
  - spec/process/daemon/process_file_spec.rb
135
+ - spec/process/daemon/terminate_spec.rb