lifeguard 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,7 +2,8 @@ language: ruby
2
2
  before_install:
3
3
  - gem install bundler
4
4
  rvm:
5
- - 1.9
6
5
  - 2.0
7
6
  - 2.1
8
- - jruby
7
+ - 2.3
8
+ - jruby-9.1.2.0
9
+ - jruby-9.1.5.0
@@ -14,16 +14,26 @@ module Lifeguard
14
14
  return false if @shutdown
15
15
 
16
16
  if busy?
17
+ job_mutex = ::Mutex.new
18
+ job_condition = ::ConditionVariable.new
17
19
  # Account for "weird" exceptions like Java Exceptions or higher up the chain
18
20
  # than what `rescue nil` will capture
19
- new_thread = ::Thread.new(block, args) do |callable, call_args|
20
- ::Thread.current[:__start_time_in_seconds__] = Time.now.to_i
21
- ::Thread.current.abort_on_exception = false
22
-
23
- callable.call(*call_args)
21
+ job_mutex.synchronize do
22
+ new_thread = ::Thread.new(block, args) do |callable, call_args|
23
+ job_mutex.synchronize do
24
+ begin
25
+ ::Thread.current[:__start_time_in_seconds__] = Time.now.to_i
26
+ ::Thread.current.abort_on_exception = false
27
+
28
+ callable.call(*call_args)
29
+ ensure
30
+ job_condition.signal
31
+ end
32
+ end
33
+ end
34
+
35
+ job_condition.wait(job_mutex)
24
36
  end
25
-
26
- ::Thread.pass while new_thread.alive?
27
37
  else
28
38
  super(*args, &block)
29
39
  end
@@ -20,7 +20,6 @@ module Lifeguard
20
20
  def run!
21
21
  loop do
22
22
  sleep(@reaping_interval)
23
- @threadpool.prune_busy_threads if @threadpool
24
23
  @threadpool.timeout! if @threadpool
25
24
  end
26
25
  rescue
@@ -24,7 +24,7 @@ module Lifeguard
24
24
  #
25
25
  @timeout = opts[:timeout]
26
26
  @mutex = ::Mutex.new
27
- @busy_threads = []
27
+ @busy_threads = ThreadGroup.new
28
28
 
29
29
  restart_reaper_unless_alive
30
30
  end
@@ -37,20 +37,12 @@ module Lifeguard
37
37
  end
38
38
 
39
39
  def busy_size
40
- @busy_threads.size
40
+ @busy_threads.list.size
41
41
  end
42
42
 
43
43
  def kill!
44
44
  @mutex.synchronize do
45
- prune_busy_threads_without_mutex
46
- @busy_threads.each { |busy_thread| busy_thread.kill }
47
- prune_busy_threads_without_mutex
48
- end
49
- end
50
-
51
- def on_thread_exit(thread)
52
- @mutex.synchronize do
53
- @busy_threads.delete(thread)
45
+ @busy_threads.list.each { |busy_thread| busy_thread.kill }
54
46
  end
55
47
  end
56
48
 
@@ -63,50 +55,26 @@ module Lifeguard
63
55
  end
64
56
 
65
57
  @mutex.synchronize do
66
- prune_busy_threads_without_mutex
67
-
68
58
  if busy_size < pool_size
69
59
  queued_the_work = true
70
60
 
71
- @busy_threads << ::Thread.new(block, args, self) do |callable, call_args, parent|
72
- begin
73
- ::Thread.current[:__start_time_in_seconds__] = Time.now.to_i
74
- ::Thread.current.abort_on_exception = false
75
- callable.call(*call_args) # should we check the args? pass args?
76
- ensure
77
- parent.on_thread_exit(::Thread.current)
78
- end
79
- end
61
+ @busy_threads.add ::Thread.new(block, args, self) { |callable, call_args, parent|
62
+ ::Thread.current.abort_on_exception = false
63
+ ::Thread.current[:__start_time_in_seconds__] = Time.now.to_i
64
+ callable.call(*call_args) # should we check the args? pass args?
65
+ }
80
66
  end
81
67
 
82
- prune_busy_threads_without_mutex
83
68
  queued_the_work
84
69
  end
85
70
  end
86
71
 
87
- def prune_busy_threads
88
- @mutex.synchronize do
89
- prune_busy_threads_without_mutex
90
- end
91
- end
72
+ def shutdown(shutdown_timeout = 3)
73
+ kill_at = Time.now.to_f + shutdown_timeout
92
74
 
93
- def shutdown(shutdown_timeout = 0)
94
75
  @mutex.synchronize do
95
- prune_busy_threads_without_mutex
96
-
97
- if @busy_threads.size > 0
98
- # Cut the shutdown_timeout by 10 and prune while things finish before the kill
99
- (shutdown_timeout/10).times do
100
- sleep (shutdown_timeout / 10.0)
101
- prune_busy_threads_without_mutex
102
- break if busy_size == 0
103
- end
104
-
105
- sleep(shutdown_timeout/10)
106
- @busy_threads.each { |busy_thread| busy_thread.kill }
107
- end
108
-
109
- prune_busy_threads_without_mutex
76
+ sleep 0.01 while busy_size > 0 && Time.now.to_f < kill_at
77
+ @busy_threads.list.each { |busy_thread| busy_thread.kill }
110
78
  end
111
79
  end
112
80
 
@@ -114,13 +82,11 @@ module Lifeguard
114
82
  return unless timeout?
115
83
 
116
84
  @mutex.synchronize do
117
- @busy_threads.each do |busy_thread|
85
+ @busy_threads.list.each do |busy_thread|
118
86
  if (Time.now.to_i - busy_thread[:__start_time_in_seconds__] > @timeout)
119
87
  busy_thread.kill
120
88
  end
121
89
  end
122
-
123
- prune_busy_threads_without_mutex
124
90
  end
125
91
  end
126
92
 
@@ -133,10 +99,6 @@ module Lifeguard
133
99
  ##
134
100
  # Private Instance Methods
135
101
  #
136
- def prune_busy_threads_without_mutex
137
- @busy_threads.select!(&:alive?)
138
- end
139
-
140
102
  def restart_reaper_unless_alive
141
103
  return if @reaper && @reaper.alive?
142
104
 
@@ -1,3 +1,3 @@
1
1
  module Lifeguard
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -45,14 +45,17 @@ describe ::Lifeguard::Threadpool do
45
45
  end
46
46
 
47
47
  it "uses the reaper to timeout threads that are all wiley" do
48
+ expected = false
48
49
  threadpool = described_class.new(:timeout => 1, :reaping_interval => 1)
49
50
  threadpool.async do
50
- sleep(10)
51
+ sleep(3)
52
+ expected = true
51
53
  end
52
54
 
53
55
  threadpool.busy_size.should eq(1)
54
56
  sleep(4)
55
57
  threadpool.busy_size.should eq(0)
58
+ expected.should be(false)
56
59
  end
57
60
  end
58
61
 
@@ -78,13 +81,12 @@ describe ::Lifeguard::Threadpool do
78
81
 
79
82
  it 'kills all threads' do
80
83
  subject
81
- before_thread_count = Thread.list.size
82
84
  100.times { subject.async{ sleep(1) } }
83
85
  sleep(0.1)
84
- Thread.list.size.should > before_thread_count
86
+ subject.busy_size.should eq(subject.pool_size)
85
87
  subject.kill!
86
88
  sleep(0.1)
87
- Thread.list.size.should eq(before_thread_count)
89
+ subject.busy_size.should eq(0)
88
90
  end
89
91
  end
90
92
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lifeguard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-09-08 00:00:00.000000000 Z
13
+ date: 2016-09-20 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: better_receive
@@ -164,7 +164,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
164
164
  version: '0'
165
165
  segments:
166
166
  - 0
167
- hash: -402206971017755019
167
+ hash: 3990094158605576821
168
168
  required_rubygems_version: !ruby/object:Gem::Requirement
169
169
  none: false
170
170
  requirements:
@@ -173,7 +173,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
173
  version: '0'
174
174
  segments:
175
175
  - 0
176
- hash: -402206971017755019
176
+ hash: 3990094158605576821
177
177
  requirements: []
178
178
  rubyforge_project:
179
179
  rubygems_version: 1.8.24