restartable 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/TODO +2 -1
- data/lib/restartable.rb +63 -36
- data/restartable.gemspec +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MWQ5YTBhNmJmNjQxOTdkZGRmZDlmOThhYWZmZmQ5MDY4OGJiMWM1Yw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZjMwMzEyMzBhYzQ0NzMyZjgyZjM3YTBhMmMzZDU5OWNhNjU2MGQ0ZA==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NzAwZmI4M2VkMzU4ZTE1ZmE5MjJiYWFmNTFjMTI3MGMyM2UzZjYxMWMxYzI1
|
10
|
+
ZDdmN2U4M2IwODdmYjYyMjJmMDUzZjc2OTkwZDk5ODY0ZWFjY2I2ZWU3NWY2
|
11
|
+
MDk0MDBiMjFkNGM0MGQ2YmUwZmYwZmZjYTNhMDk4MGE2NDM4MjM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZTczZDEwNzY1MDg3Y2VhOTI4OTVkNzA0NzlhM2FlMjYyN2VlYzhiODc4Yjlm
|
14
|
+
YmQ5NzFjYmMxNjA2N2ZjZTkzNzFkZTc0ODY4MTNlNGIzZGE5MDM3YjI2ZWVm
|
15
|
+
ZTM2ZDVhOGQxZmE2ZmZjODA4YTJiZDdiODVlMDcyZjY0MTE5ZTU=
|
data/TODO
CHANGED
data/lib/restartable.rb
CHANGED
@@ -2,82 +2,109 @@
|
|
2
2
|
|
3
3
|
require 'sys/proctable'
|
4
4
|
require 'colored'
|
5
|
+
require 'thread'
|
5
6
|
|
6
7
|
class Restartable
|
7
8
|
def self.version
|
8
9
|
Gem.loaded_specs['restartable'].version.to_s rescue 'DEV'
|
9
10
|
end
|
10
11
|
|
11
|
-
WAIT_SIGNALS = [[1, 'INT'], [1, 'INT'], [1, 'INT'], [1, 'TERM'], [5, 'KILL']]
|
12
|
-
|
13
12
|
def initialize(options, &block)
|
14
13
|
@options, @block = options, block
|
14
|
+
run!
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def run!
|
15
20
|
@mutex = Mutex.new
|
16
|
-
|
17
|
-
|
21
|
+
|
22
|
+
receiver, sender = IO.pipe
|
23
|
+
@trap_sender = Process.fork do
|
24
|
+
receiver.close
|
25
|
+
Signal.trap('PIPE', 'EXIT')
|
26
|
+
synced_trap('INT'){ Marshal.dump(:int, sender) }
|
27
|
+
loop{ sleep }
|
28
|
+
end
|
29
|
+
sender.close
|
30
|
+
|
31
|
+
Signal.trap('INT', 'IGNORE')
|
32
|
+
synced_trap('TERM'){ terminate! }
|
33
|
+
|
34
|
+
int_receiver = Thread.new do
|
35
|
+
until receiver.eof?
|
36
|
+
Marshal.load(receiver) && interrupt!
|
37
|
+
end
|
38
|
+
end
|
18
39
|
cycle
|
19
40
|
end
|
20
41
|
|
21
42
|
def interrupt!
|
22
43
|
unless @interrupted
|
23
44
|
@interrupted = true
|
24
|
-
Thread.list.each do |thread|
|
25
|
-
|
26
|
-
thread.raise SignalException.new('INT')
|
27
|
-
end
|
45
|
+
(Thread.list - [Thread.current]).each do |thread|
|
46
|
+
thread.raise SignalException.new('INT')
|
28
47
|
end
|
29
48
|
else
|
30
49
|
no_restart!
|
31
50
|
end
|
32
51
|
end
|
33
52
|
|
53
|
+
def terminate!
|
54
|
+
no_restart!
|
55
|
+
interrupt!
|
56
|
+
end
|
57
|
+
|
34
58
|
def no_restart!
|
35
59
|
@stop = true
|
36
60
|
puts 'Don\'t restart!'.red.bold
|
37
61
|
end
|
38
62
|
|
63
|
+
def synced_trap(signal, &block)
|
64
|
+
Signal.trap(signal) do
|
65
|
+
Thread.new do
|
66
|
+
@mutex.synchronize(&block)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
WAIT_SIGNALS = [[5, 'INT'], [3, 'INT'], [1, 'INT'], [3, 'TERM'], [5, 'KILL']]
|
72
|
+
|
39
73
|
def cycle
|
40
74
|
until @stop
|
41
75
|
@interrupted = false
|
42
76
|
puts '^C to restart, double ^C to stop'.green
|
43
77
|
begin
|
44
78
|
@block.call
|
45
|
-
sleep # wait ^C even if block finishes
|
79
|
+
loop{ sleep } # wait ^C even if block finishes
|
46
80
|
rescue SignalException
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
puts "…SIG#{signal}…".yellow
|
53
|
-
children.each do |child|
|
54
|
-
Process.kill(signal, child.pid)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
Process.waitall
|
59
|
-
ripper.terminate
|
60
|
-
end
|
61
|
-
unless @stop
|
62
|
-
puts 'Waiting ^C 0.5 second than restart…'.yellow.bold
|
63
|
-
sleep 0.5
|
64
|
-
end
|
81
|
+
kill_children!
|
82
|
+
end
|
83
|
+
unless @stop
|
84
|
+
puts 'Waiting ^C 0.5 second than restart…'.yellow.bold
|
85
|
+
sleep 0.5
|
65
86
|
end
|
66
87
|
end
|
67
88
|
end
|
68
89
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
90
|
+
def kill_children!
|
91
|
+
unless children_pids.empty?
|
92
|
+
puts 'Killing children…'.yellow.bold
|
93
|
+
ripper = Thread.new do
|
94
|
+
WAIT_SIGNALS.each do |time, signal|
|
95
|
+
sleep time
|
96
|
+
puts "…SIG#{signal}…".yellow
|
97
|
+
children_pids.each do |child_pid|
|
98
|
+
Process.kill(signal, child_pid)
|
99
|
+
end
|
100
|
+
end
|
75
101
|
end
|
102
|
+
children_pids.each(&Process.method(:wait))
|
103
|
+
ripper.terminate
|
76
104
|
end
|
77
105
|
end
|
78
106
|
|
79
|
-
def
|
80
|
-
|
81
|
-
Sys::ProcTable.ps.select{ |pe| pid == pe.ppid }
|
107
|
+
def children_pids
|
108
|
+
Sys::ProcTable.ps.select{ |pe| $$ == pe.ppid }.map(&:pid) - [@trap_sender]
|
82
109
|
end
|
83
110
|
end
|
data/restartable.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: restartable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Kuchin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-04-
|
11
|
+
date: 2013-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colored
|