sponges 0.5.0.pre → 0.5.0
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.md +5 -0
- data/lib/sponges.rb +4 -1
- data/lib/sponges/cli.rb +1 -0
- data/lib/sponges/commander.rb +1 -6
- data/lib/sponges/handler.rb +126 -0
- data/lib/sponges/runner.rb +0 -1
- data/lib/sponges/store/memory.rb +0 -2
- data/lib/sponges/supervisor.rb +12 -80
- data/lib/sponges/version.rb +1 -1
- metadata +7 -5
data/README.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# sponges
|
2
2
|
|
3
|
+
[](https://codeclimate.com/github/AF83/sponges)
|
5
|
+
[](http://badge.fury.io/rb/sponges)
|
7
|
+
|
3
8
|
When I build workers, I want them to be like an army of spongebobs, always
|
4
9
|
stressed and eager to work. `sponges` helps you build this army of sponges, to
|
5
10
|
control them, and, well, to kill them gracefully. Making them stressed and eager
|
data/lib/sponges.rb
CHANGED
@@ -3,7 +3,9 @@ require 'boson/runner'
|
|
3
3
|
require 'socket'
|
4
4
|
require 'logger'
|
5
5
|
require 'machine'
|
6
|
+
require 'forwardable'
|
6
7
|
require_relative 'sponges/configuration'
|
8
|
+
require_relative 'sponges/handler'
|
7
9
|
require_relative 'sponges/supervisor'
|
8
10
|
require_relative 'sponges/runner'
|
9
11
|
require_relative 'sponges/commander'
|
@@ -13,7 +15,8 @@ require_relative 'sponges/store/memory'
|
|
13
15
|
require_relative 'sponges/store/redis'
|
14
16
|
|
15
17
|
module Sponges
|
16
|
-
|
18
|
+
STOP_SIGNALS = [:INT, :QUIT, :TERM]
|
19
|
+
SIGNALS = STOP_SIGNALS + [:HUP, :TTIN, :TTOU, :CHLD]
|
17
20
|
|
18
21
|
def configure(&block)
|
19
22
|
Sponges::Configuration.configure &block
|
data/lib/sponges/cli.rb
CHANGED
data/lib/sponges/commander.rb
CHANGED
@@ -0,0 +1,126 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Sponges
|
3
|
+
class Handler
|
4
|
+
extend Forwardable
|
5
|
+
attr_reader :supervisor
|
6
|
+
|
7
|
+
def initialize(supervisor)
|
8
|
+
@supervisor = supervisor
|
9
|
+
at_exit do
|
10
|
+
for_supervisor do
|
11
|
+
Sponges.logger.info "Supervisor exits."
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(signal)
|
17
|
+
if Sponges::SIGNALS.include?(signal = find_signal(signal))
|
18
|
+
send "handler_#{signal.to_s.downcase}", signal
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def_delegators :@supervisor, :store, :fork_children, :name, :children_name
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def for_supervisor
|
27
|
+
yield if Process.pid == store.supervisor_pid
|
28
|
+
end
|
29
|
+
|
30
|
+
def find_signal(signal)
|
31
|
+
return signal if signal.is_a?(Symbol)
|
32
|
+
if signal = Signal.list.find {|k,v| v == signal }
|
33
|
+
signal.first.to_sym
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def handler_ttin(signal)
|
38
|
+
for_supervisor do
|
39
|
+
Sponges.logger.warn "Supervisor increment child's pool by one."
|
40
|
+
fork_children
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def handler_ttou(signal)
|
45
|
+
for_supervisor do
|
46
|
+
Sponges.logger.warn "Supervisor decrement child's pool by one."
|
47
|
+
if store.children_pids.first
|
48
|
+
kill_one(store.children_pids.first, :HUP)
|
49
|
+
store.delete_children(store.children_pids.first)
|
50
|
+
else
|
51
|
+
Sponges.logger.warn "No more child to kill."
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def handler_chld(signal)
|
57
|
+
for_supervisor do
|
58
|
+
return if stopping?
|
59
|
+
store.children_pids.each do |pid|
|
60
|
+
begin
|
61
|
+
if dead = Process.waitpid(pid.to_i, Process::WNOHANG)
|
62
|
+
store.delete_children dead
|
63
|
+
Sponges.logger.warn "Child #{dead} died. Restarting a new one..."
|
64
|
+
Sponges::Hook.on_chld
|
65
|
+
fork_children
|
66
|
+
end
|
67
|
+
rescue Errno::ECHILD => e
|
68
|
+
# Don't panic
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def handler_int(signal)
|
75
|
+
for_supervisor do
|
76
|
+
@stopping = true
|
77
|
+
Sponges.logger.info "Supervisor received #{signal} signal."
|
78
|
+
kill_them_all(signal) and shutdown
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
alias handler_quit handler_int
|
83
|
+
alias handler_term handler_int
|
84
|
+
|
85
|
+
def kill_them_all(signal)
|
86
|
+
store.children_pids.map do |pid|
|
87
|
+
Thread.new { kill_one(pid.to_i, signal) }
|
88
|
+
end.each &:join
|
89
|
+
end
|
90
|
+
|
91
|
+
def kill_one(pid, signal)
|
92
|
+
begin
|
93
|
+
Process.kill signal, pid
|
94
|
+
Process.waitpid pid
|
95
|
+
Sponges.logger.info "Child #{pid} receive a #{signal} signal."
|
96
|
+
rescue Errno::ESRCH, Errno::ECHILD, SignalException => e
|
97
|
+
# Don't panic
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def shutdown
|
102
|
+
Process.waitall
|
103
|
+
Sponges.logger.info "Children shutdown complete.", "Supervisor shutdown. Exiting..."
|
104
|
+
store.clear(name)
|
105
|
+
exit
|
106
|
+
rescue Errno::ESRCH, Errno::ECHILD, SignalException => e
|
107
|
+
# Don't panic
|
108
|
+
end
|
109
|
+
|
110
|
+
def fork_children
|
111
|
+
name = children_name
|
112
|
+
pid = fork do
|
113
|
+
$PROGRAM_NAME = name
|
114
|
+
(Sponges::STOP_SIGNALS + [:HUP]).each{ |sig| trap(sig) { exit!(0) } }
|
115
|
+
Sponges::Hook.after_fork
|
116
|
+
supervisor.call
|
117
|
+
end
|
118
|
+
Sponges.logger.info "Supervisor create a child with #{pid} pid."
|
119
|
+
store.add_children pid
|
120
|
+
end
|
121
|
+
|
122
|
+
def stopping?
|
123
|
+
@stopping
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/sponges/runner.rb
CHANGED
data/lib/sponges/store/memory.rb
CHANGED
data/lib/sponges/supervisor.rb
CHANGED
@@ -1,113 +1,45 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module Sponges
|
3
3
|
class Supervisor
|
4
|
-
attr_reader :store, :name, :options
|
4
|
+
attr_reader :store, :name, :options, :handler
|
5
5
|
|
6
6
|
def initialize(name, options, store, block)
|
7
7
|
@name, @options, @store, @block = name, options, store, block
|
8
|
+
$PROGRAM_NAME = "#{@name}_supervisor"
|
8
9
|
store.on_fork
|
9
10
|
store.register Process.pid
|
10
11
|
@children_seen = 0
|
12
|
+
@handler = Handler.new self
|
11
13
|
end
|
12
14
|
|
13
15
|
def start
|
16
|
+
trap_signals
|
14
17
|
options[:size].times do
|
15
|
-
|
16
|
-
end
|
17
|
-
Thread.new do
|
18
|
-
trap_signals
|
19
|
-
at_exit do
|
20
|
-
Sponges.logger.info "Supervisor exits."
|
21
|
-
end
|
18
|
+
handler.call :TTIN
|
22
19
|
end
|
23
20
|
Sponges.logger.info "Supervisor started, waiting for messages."
|
24
21
|
sleep
|
25
22
|
rescue Exception => exception
|
26
23
|
Sponges.logger.error exception
|
27
|
-
|
24
|
+
handler.call :INT
|
28
25
|
raise exception
|
29
26
|
end
|
30
27
|
|
31
|
-
|
32
|
-
|
33
|
-
def fork_children
|
34
|
-
name = children_name
|
35
|
-
pid = fork do
|
36
|
-
$PROGRAM_NAME = name
|
37
|
-
Sponges::Hook.after_fork
|
38
|
-
@block.call
|
39
|
-
end
|
40
|
-
Sponges.logger.info "Supervisor create a child with #{pid} pid."
|
41
|
-
store.add_children pid
|
28
|
+
def call
|
29
|
+
@block.call
|
42
30
|
end
|
43
31
|
|
32
|
+
private
|
33
|
+
|
44
34
|
def children_name
|
45
35
|
"#{name}_child_#{@children_seen +=1}"
|
46
36
|
end
|
47
37
|
|
48
38
|
def trap_signals
|
49
|
-
|
50
|
-
trap(signal)
|
51
|
-
handle_signal signal
|
52
|
-
end
|
53
|
-
end
|
54
|
-
trap(:TTIN) do
|
55
|
-
Sponges.logger.warn "Supervisor increment child's pool by one."
|
56
|
-
fork_children
|
57
|
-
end
|
58
|
-
trap(:TTOU) do
|
59
|
-
Sponges.logger.warn "Supervisor decrement child's pool by one."
|
60
|
-
if store.children_pids.first
|
61
|
-
kill_one(store.children_pids.first, :HUP)
|
62
|
-
store.delete_children(store.children_pids.first)
|
63
|
-
else
|
64
|
-
Sponges.logger.warn "No more child to kill."
|
65
|
-
end
|
66
|
-
end
|
67
|
-
trap(:CHLD) do
|
68
|
-
store.children_pids.each do |pid|
|
69
|
-
begin
|
70
|
-
dead = Process.waitpid(pid.to_i, Process::WNOHANG)
|
71
|
-
if dead
|
72
|
-
Sponges.logger.warn "Child #{dead} died. Restarting a new one..."
|
73
|
-
store.delete_children dead
|
74
|
-
Sponges::Hook.on_chld
|
75
|
-
fork_children
|
76
|
-
end
|
77
|
-
rescue Errno::ECHILD => e
|
78
|
-
# Don't panic
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def handle_signal(signal)
|
85
|
-
Sponges.logger.info "Supervisor received #{signal} signal."
|
86
|
-
kill_them_all(signal)
|
87
|
-
Process.waitall
|
88
|
-
Sponges.logger.info "Children shutdown complete."
|
89
|
-
Sponges.logger.info "Supervisor shutdown. Exiting..."
|
90
|
-
pid = store.supervisor_pid
|
91
|
-
store.clear(name)
|
92
|
-
Process.kill :USR1, pid.to_i
|
93
|
-
end
|
94
|
-
|
95
|
-
def kill_them_all(signal)
|
96
|
-
store.children_pids.each do |pid|
|
97
|
-
Thread.new do
|
98
|
-
kill_one(pid.to_i, signal)
|
99
|
-
end
|
39
|
+
Sponges::SIGNALS.each do |signal|
|
40
|
+
trap(signal) {|signal| handler.call signal }
|
100
41
|
end
|
101
42
|
end
|
102
43
|
|
103
|
-
def kill_one(pid, signal)
|
104
|
-
begin
|
105
|
-
Process.kill signal, pid
|
106
|
-
Process.waitpid pid
|
107
|
-
Sponges.logger.info "Child #{pid} receive a #{signal} signal."
|
108
|
-
rescue Errno::ESRCH, Errno::ECHILD, SignalException => e
|
109
|
-
# Don't panic
|
110
|
-
end
|
111
|
-
end
|
112
44
|
end
|
113
45
|
end
|
data/lib/sponges/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sponges
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.0
|
5
|
-
prerelease:
|
4
|
+
version: 0.5.0
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- chatgris
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-02-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: boson
|
@@ -75,6 +75,7 @@ files:
|
|
75
75
|
- lib/sponges/cli.rb
|
76
76
|
- lib/sponges/commander.rb
|
77
77
|
- lib/sponges/configuration.rb
|
78
|
+
- lib/sponges/handler.rb
|
78
79
|
- lib/sponges/runner.rb
|
79
80
|
- lib/sponges/store.rb
|
80
81
|
- lib/sponges/store/memory.rb
|
@@ -96,9 +97,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
96
97
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
98
|
none: false
|
98
99
|
requirements:
|
99
|
-
- - ! '
|
100
|
+
- - ! '>='
|
100
101
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
102
|
+
version: '0'
|
102
103
|
requirements: []
|
103
104
|
rubyforge_project:
|
104
105
|
rubygems_version: 1.8.24
|
@@ -106,3 +107,4 @@ signing_key:
|
|
106
107
|
specification_version: 3
|
107
108
|
summary: Turn any ruby object to a daemon controlling an army of sponges.
|
108
109
|
test_files: []
|
110
|
+
has_rdoc:
|