sponges 0.5.0.pre → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # sponges
2
2
 
3
+ [![Code
4
+ Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/AF83/sponges)
5
+ [![Gem
6
+ Version](https://fury-badge.herokuapp.com/rb/sponges.png)](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
- SIGNALS = [:INT, :QUIT, :TERM]
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
@@ -39,6 +39,7 @@ module Sponges
39
39
  desc "Restart workers"
40
40
  def restart(options = {})
41
41
  stop(options)
42
+ sleep 1
42
43
  start(options)
43
44
  end
44
45
 
@@ -106,12 +106,7 @@ module Sponges
106
106
  end
107
107
 
108
108
  def alive?(pid)
109
- begin
110
- Process.kill 0, pid
111
- true
112
- rescue Errno::ESRCH => e
113
- false
114
- end
109
+ !Sys::ProcTable.ps.find {|f| f.pid == pid }.nil?
115
110
  end
116
111
 
117
112
  def gracefully?
@@ -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
@@ -50,7 +50,6 @@ module Sponges
50
50
 
51
51
  def fork_supervisor
52
52
  fork do
53
- $PROGRAM_NAME = "#{@name}_supervisor"
54
53
  Supervisor.new(@name, @options, store, @block).start
55
54
  end
56
55
  end
@@ -1,6 +1,4 @@
1
1
  # encoding: utf-8
2
- require 'forwardable'
3
-
4
2
  module Sponges
5
3
  class Store
6
4
  class Memory
@@ -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
- fork_children
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
- kill_them_all(:INT)
24
+ handler.call :INT
28
25
  raise exception
29
26
  end
30
27
 
31
- private
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
- (Sponges::SIGNALS + [:HUP]).each do |signal|
50
- trap(signal) do
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
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Sponges
3
- VERSION = "0.5.0.pre"
3
+ VERSION = "0.5.0"
4
4
  end
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.pre
5
- prerelease: 6
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-01-28 00:00:00.000000000 Z
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: 1.3.1
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: