rest-core 3.5.2 → 3.5.3

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: 0399835474967a9425ce60b8073d0b4a49e7c572
4
- data.tar.gz: 6cac1d0a2fce2e8f5ea64e64b2b56343d8e61368
3
+ metadata.gz: fe0c761a5d6c0bc856f35b558c9f70a74ac36815
4
+ data.tar.gz: 27c1295dc0082285072cfcd618afca9f5bf3b39f
5
5
  SHA512:
6
- metadata.gz: 5beda3343160e6e04d7df902f702a6d99aa02ef49c6e7d9085d398c76ec07d518e096af779bdbf336a6e2b80fe20438f630676b4c97cd20706d990d0a263c5db
7
- data.tar.gz: 1ee0950dd782a66de5bf11fe8e5cf4f7a42da6717883a7d25c58be37abb7c38d7ad5b1334bef1325b45e42eafd46d250ae0b928d4846757af0bfc7fe90019c1d
6
+ metadata.gz: c771af63c6cbc5b9ab95043aafedf83aa1e56c56e0179696a828a03b41dcf61cfb7f934db1e40a9e31632ae263e29ad62cdc87223d759603b1be6ac7b9e29154
7
+ data.tar.gz: ae1f3a83d67d4790a0805fd77261d2eee610eb62680b076ff754691ce6cbf64b3a86871b84ebcf1f6a0b2d4247eb174784a65c7b0f8c76e5acd83008a3353050
data/CHANGES.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # CHANGES
2
2
 
3
+ ## rest-core 3.5.3 -- 2015-01-11
4
+
5
+ ### Bugs fixed
6
+
7
+ * Fixed a regression where timeout is not properly handled for thread pool.
8
+
3
9
  ## rest-core 3.5.2 -- 2015-01-09
4
10
 
5
11
  ### Bugs fixed
@@ -68,12 +68,16 @@ class RestCore::Promise
68
68
  self.thread = Thread.current # set working thread
69
69
  protected_yield{ yield } # avoid any exception and do the job
70
70
  else
71
- backtrace = caller + self.class.backtrace
71
+ backtrace = caller + self.class.backtrace # retain the backtrace so far
72
72
  if pool_size > 0
73
- self.task = client_class.thread_pool.defer(mutex) do
74
- Thread.current[:backtrace] = backtrace
75
- protected_yield{ yield }
76
- Thread.current[:backtrace] = nil
73
+ mutex.synchronize do
74
+ # still timing it out if the task never processed
75
+ env[TIMER].on_timeout{ cancel_task } if env[TIMER]
76
+ self.task = client_class.thread_pool.defer(mutex) do
77
+ Thread.current[:backtrace] = backtrace
78
+ protected_yield{ yield }
79
+ Thread.current[:backtrace] = nil
80
+ end
77
81
  end
78
82
  else
79
83
  self.thread = Thread.new do
@@ -162,7 +166,7 @@ class RestCore::Promise
162
166
  callback_error(e)
163
167
  else # IOError, SystemCallError, etc
164
168
  begin
165
- rejecting(e)
169
+ rejecting(e) # would call user callback
166
170
  rescue Exception => f # log user callback error
167
171
  callback_error(f){ self.class.set_backtrace(f) }
168
172
  end
@@ -171,7 +175,8 @@ class RestCore::Promise
171
175
  end
172
176
 
173
177
  def timeout_protected_yield
174
- env[TIMER].on_timeout{ cancel_task } # set timeout
178
+ # timeout might already be set for thread_pool (pool_size > 0)
179
+ env[TIMER].on_timeout{ cancel_task } unless env[TIMER].timer
175
180
  yield
176
181
  ensure
177
182
  env[TIMER].cancel
@@ -210,7 +215,7 @@ class RestCore::Promise
210
215
  if t = thread || task.thread
211
216
  t.raise(env[TIMER].error) # raise Timeout::Error to working thread
212
217
  else # task was queued and never started, just cancel it and
213
- begin # fulfil the promise with Timeout::Error
218
+ begin # fulfill the promise with Timeout::Error
214
219
  task.cancel
215
220
  rejecting(env[TIMER].error)
216
221
  rescue Exception => e # log user callback error
@@ -88,12 +88,10 @@ class RestCore::ThreadPool
88
88
  end
89
89
 
90
90
  def defer mutex=nil, &job
91
- mutex.synchronize do
92
- task = Task.new(job, mutex)
93
- queue << task
94
- spawn_worker if waiting == 0 && workers.size < max_size
95
- task
96
- end
91
+ task = Task.new(job, mutex)
92
+ queue << task
93
+ spawn_worker if waiting == 0 && workers.size < max_size
94
+ task
97
95
  end
98
96
 
99
97
  def trim force=false
@@ -29,7 +29,7 @@ class RestCore::Timer
29
29
  end
30
30
  end
31
31
 
32
- attr_accessor :timeout, :error
32
+ attr_accessor :timeout, :error, :timer
33
33
  def initialize timeout, error, &block
34
34
  self.timeout = timeout
35
35
  self.error = error
@@ -54,5 +54,5 @@ class RestCore::Timer
54
54
  end
55
55
 
56
56
  protected
57
- attr_accessor :block, :timer
57
+ attr_accessor :block
58
58
  end
@@ -1,4 +1,4 @@
1
1
 
2
2
  module RestCore
3
- VERSION = '3.5.2'
3
+ VERSION = '3.5.3'
4
4
  end
@@ -1,14 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: rest-core 3.5.2 ruby lib
2
+ # stub: rest-core 3.5.3 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "rest-core"
6
- s.version = "3.5.2"
6
+ s.version = "3.5.3"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib"]
10
10
  s.authors = ["Lin Jen-Shin (godfat)"]
11
- s.date = "2015-01-09"
11
+ s.date = "2015-01-11"
12
12
  s.description = "Modular Ruby clients interface for REST APIs.\n\nThere has been an explosion in the number of REST APIs available today.\nTo address the need for a way to access these APIs easily and elegantly,\nwe have developed rest-core, which consists of composable middleware\nthat allows you to build a REST client for any REST API. Or in the case of\ncommon APIs such as Facebook, Github, and Twitter, you can simply use the\ndedicated clients provided by [rest-more][].\n\n[rest-more]: https://github.com/godfat/rest-more"
13
13
  s.email = ["godfat (XD) godfat.org"]
14
14
  s.files = [
@@ -28,36 +28,61 @@ describe RC::Timeout do
28
28
  lambda{ sleep 0.01 }.should.not.raise(Timeout::Error)
29
29
  end
30
30
 
31
- would 'cancel the task if timing out' do
32
- timer = Object.new.instance_eval do
33
- def on_timeout; yield ; end
31
+ def fake_timer
32
+ Object.new.instance_eval do
33
+ @block = nil
34
+ def on_timeout; @block = true; Thread.new{yield}; end
34
35
  def error ; 'boom'; end
35
36
  def cancel ; ; end
37
+ def timer ; @block; end
36
38
  self
37
39
  end
38
- app = RC::Builder.client do
40
+ end
41
+
42
+ def sleeping_app
43
+ RC::Builder.client do
39
44
  run Class.new(RC::Engine){
40
45
  def request _, _
41
46
  sleep
42
47
  end
43
48
  }
44
49
  end
50
+ end
51
+
52
+ would 'cancel the task if timing out for thread pool' do
53
+ timer = fake_timer
54
+ app = sleeping_app
45
55
  app.pool_size = 1
46
56
  app.new.request(RC::TIMER => timer, RC::ASYNC => true).
47
57
  message.should.eq 'boom'
58
+ timer.timer.should.not.nil?
59
+ end
60
+
61
+ would 'still timeout if the task never processed for thread pool' do
62
+ app = sleeping_app
63
+ app.pool_size = 1
64
+ app.new.request(RC::TIMER => fake_timer, RC::ASYNC => true) do |e|
65
+ e.message.should.eq 'boom'
66
+ app.new.request(RC::TIMER => fake_timer, RC::ASYNC => true).tap{}
67
+ end
68
+ app.wait
48
69
  end
49
70
 
50
71
  would 'interrupt the task if timing out' do
51
72
  rd, wr = IO.pipe
52
73
  timer = Object.new.instance_eval do
74
+ @block = nil
53
75
  define_singleton_method :on_timeout do |&block|
76
+ @block = block
54
77
  Thread.new do
55
78
  rd.gets
56
79
  block.call
80
+ @block = nil
57
81
  end
58
82
  end
59
83
  def error ; 'boom'; end
60
84
  def cancel ; ; end
85
+ def timer ; @block; end
61
86
  self
62
87
  end
63
88
  app = RC::Builder.client do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.5.2
4
+ version: 3.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lin Jen-Shin (godfat)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-09 00:00:00.000000000 Z
11
+ date: 2015-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httpclient