rest-core 3.5.1 → 3.5.2

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: 0deea3c56ae01f19f5d7f7d6b32a6ea35259846b
4
- data.tar.gz: ce45a4ddcadda96dfecec4ad2ad24079f5fedcb9
3
+ metadata.gz: 0399835474967a9425ce60b8073d0b4a49e7c572
4
+ data.tar.gz: 6cac1d0a2fce2e8f5ea64e64b2b56343d8e61368
5
5
  SHA512:
6
- metadata.gz: 6b1f3bd1b3b254cd7c922dddebe618f134c4cf2d328b018584b0390410adc1218b8bf6333f163ddd9698a54d88347ef5d3fdb850e7b50c3cc7ba63b7a0797457
7
- data.tar.gz: 0314d2a3658e30486a13d7e9ffbb9fd8d63d8fd1f5711fb38cd5c99b26576bb9af4698b337e1f97320b9ab35c51c0bffe556da73f6837483518971cfc414a9b8
6
+ metadata.gz: 5beda3343160e6e04d7df902f702a6d99aa02ef49c6e7d9085d398c76ec07d518e096af779bdbf336a6e2b80fe20438f630676b4c97cd20706d990d0a263c5db
7
+ data.tar.gz: 1ee0950dd782a66de5bf11fe8e5cf4f7a42da6717883a7d25c58be37abb7c38d7ad5b1334bef1325b45e42eafd46d250ae0b928d4846757af0bfc7fe90019c1d
@@ -1,13 +1,12 @@
1
- language: ruby
2
1
 
2
+ language: ruby
3
3
  rvm:
4
4
  - 2.0
5
5
  - 2.1
6
6
  - 2.2
7
7
  - rbx-2
8
8
  - jruby
9
+ - jruby-head
9
10
 
10
11
  install: 'bundle install --retry=3'
11
12
  script: 'ruby -r bundler/setup -S rake test'
12
-
13
- sudo: false
data/CHANGES.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # CHANGES
2
2
 
3
+ ## rest-core 3.5.2 -- 2015-01-09
4
+
5
+ ### Bugs fixed
6
+
7
+ * Now callbacks would respect `RC::RESPONSE_KEY`.
8
+ * Clear `Thread.current[:backtrace]` after done in thread pool to reduce
9
+ memory footprint.
10
+ * Fixed backtrace for exception raised in callbacks.
11
+ * Fixed some potential corner cases where errors are not properly handled
12
+ when timeout happened.
13
+
3
14
  ## rest-core 3.5.1 -- 2014-12-27
4
15
 
5
16
  * Ruby 2.2 compatibility.
@@ -214,11 +214,7 @@ module RestCore::Client
214
214
  RC::Promise.set_backtrace(err) unless err.backtrace
215
215
  error_callback.call(err) if error_callback
216
216
  if res[ASYNC]
217
- if res[HIJACK]
218
- res.merge(RESPONSE_SOCKET => err)
219
- else
220
- res.merge(RESPONSE_BODY => err)
221
- end
217
+ res.merge(response_key(res) => err)
222
218
  else
223
219
  raise err
224
220
  end
@@ -65,16 +65,15 @@ class RestCore::Promise
65
65
  # called in client thread
66
66
  def defer
67
67
  if pool_size < 0 # negative number for blocking call
68
- self.thread = Thread.current
69
- # set timeout after thread set, before yield (because yield is blocking)
70
- env[TIMER].on_timeout{ cancel_task } if env[TIMER]
71
- protected_yield{ yield }
68
+ self.thread = Thread.current # set working thread
69
+ protected_yield{ yield } # avoid any exception and do the job
72
70
  else
73
71
  backtrace = caller + self.class.backtrace
74
72
  if pool_size > 0
75
73
  self.task = client_class.thread_pool.defer(mutex) do
76
74
  Thread.current[:backtrace] = backtrace
77
75
  protected_yield{ yield }
76
+ Thread.current[:backtrace] = nil
78
77
  end
79
78
  else
80
79
  self.thread = Thread.new do
@@ -82,8 +81,6 @@ class RestCore::Promise
82
81
  protected_yield{ yield }
83
82
  end
84
83
  end
85
- # set timeout after thread/task set
86
- env[TIMER].on_timeout{ cancel_task } if env[TIMER]
87
84
  end
88
85
  end
89
86
 
@@ -153,32 +150,31 @@ class RestCore::Promise
153
150
  # called in a new thread if pool_size == 0, otherwise from the pool
154
151
  # i.e. requesting thread
155
152
  def protected_yield
156
- yield
153
+ if env[TIMER]
154
+ timeout_protected_yield{ yield }
155
+ else
156
+ yield
157
+ end
157
158
  rescue Exception => e
158
159
  mutex.synchronize do
159
- never_raise_yield do
160
- env[TIMER].cancel if env[TIMER]
161
- self.class.set_backtrace(e)
162
- end
163
-
164
- if done?
160
+ self.class.set_backtrace(e)
161
+ if done? # log user callback error
165
162
  callback_error(e)
166
- else
163
+ else # IOError, SystemCallError, etc
167
164
  begin
168
- rejecting(e) # i/o error
169
- rescue Exception => e
170
- callback_error(e)
165
+ rejecting(e)
166
+ rescue Exception => f # log user callback error
167
+ callback_error(f){ self.class.set_backtrace(f) }
171
168
  end
172
169
  end
173
170
  end
174
171
  end
175
172
 
176
- # only use this for unimportant stuffs and in most critical section
177
- # e.g. error logging in critical section
178
- def never_raise_yield
173
+ def timeout_protected_yield
174
+ env[TIMER].on_timeout{ cancel_task } # set timeout
179
175
  yield
180
- rescue Exception => e
181
- Thread.main.raise(e) if !!$DEBUG
176
+ ensure
177
+ env[TIMER].cancel
182
178
  end
183
179
 
184
180
  # called in client thread, when yield is called
@@ -195,8 +191,10 @@ class RestCore::Promise
195
191
  self.called = true
196
192
  end
197
193
 
194
+ # log user callback error
198
195
  def callback_error e
199
196
  never_raise_yield do
197
+ yield if block_given?
200
198
  if env[CLIENT].error_callback
201
199
  env[CLIENT].error_callback.call(e)
202
200
  else
@@ -205,18 +203,31 @@ class RestCore::Promise
205
203
  end
206
204
  end
207
205
 
208
- def cancel_task
206
+ # timeout!
207
+ def cancel_task backtrace=nil
209
208
  mutex.synchronize do
210
- next if done?
209
+ next if done? # don't cancel if it's done
211
210
  if t = thread || task.thread
212
- t.raise(env[TIMER].error)
213
- else
214
- task.cancel
215
- rejecting(env[TIMER].error)
211
+ t.raise(env[TIMER].error) # raise Timeout::Error to working thread
212
+ else # task was queued and never started, just cancel it and
213
+ begin # fulfil the promise with Timeout::Error
214
+ task.cancel
215
+ rejecting(env[TIMER].error)
216
+ rescue Exception => e # log user callback error
217
+ callback_error(e){e.set_backtrace(e.backtrace + (backtrace || []))}
218
+ end
216
219
  end
217
220
  end
218
221
  end
219
222
 
223
+ # only use this for unimportant stuffs and in most critical section
224
+ # e.g. error logging in critical section
225
+ def never_raise_yield
226
+ yield
227
+ rescue Exception => e
228
+ Thread.main.raise(e) if !!$DEBUG
229
+ end
230
+
220
231
  def client_class; env[CLIENT].class; end
221
232
  def pool_size
222
233
  @pool_size ||= if client_class.respond_to?(:pool_size)
@@ -34,16 +34,17 @@ class RestCore::Timer
34
34
  self.timeout = timeout
35
35
  self.error = error
36
36
  self.block = block
37
- start
37
+ start if block_given?
38
38
  end
39
39
 
40
40
  def on_timeout &block
41
41
  self.block = block
42
+ start if block_given?
42
43
  end
43
44
 
44
45
  # should never raise!
45
46
  def cancel
46
- timer.cancel
47
+ timer.cancel if timer
47
48
  self.block = nil
48
49
  end
49
50
 
@@ -1,4 +1,4 @@
1
1
 
2
2
  module RestCore
3
- VERSION = '3.5.1'
3
+ VERSION = '3.5.2'
4
4
  end
@@ -1,14 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: rest-core 3.5.1 ruby lib
2
+ # stub: rest-core 3.5.2 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "rest-core"
6
- s.version = "3.5.1"
6
+ s.version = "3.5.2"
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 = "2014-12-27"
11
+ s.date = "2015-01-09"
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 = [
@@ -40,8 +40,7 @@ describe RC::HttpClient do
40
40
 
41
41
  would 'not kill the thread if error was coming from the task' do
42
42
  mock(HTTPClient).new{ raise 'boom' }.with_any_args
43
- c.request(RC::RESPONSE_KEY => RC::FAIL,
44
- RC::ASYNC => true).first.message.should.eq 'boom'
43
+ c.request(RC::ASYNC => true).message.should.eq 'boom'
45
44
  Muack.verify
46
45
  end
47
46
  end
@@ -43,9 +43,8 @@ describe RC::Timeout do
43
43
  }
44
44
  end
45
45
  app.pool_size = 1
46
- app.new.request(RC::RESPONSE_KEY => RC::FAIL, RC::TIMER => timer,
47
- RC::ASYNC => true).
48
- first.message.should.eq 'boom'
46
+ app.new.request(RC::TIMER => timer, RC::ASYNC => true).
47
+ message.should.eq 'boom'
49
48
  end
50
49
 
51
50
  would 'interrupt the task if timing out' do
@@ -71,9 +70,8 @@ describe RC::Timeout do
71
70
  end
72
71
  (-1..1).each do |size|
73
72
  app.pool_size = size
74
- app.new.request(RC::RESPONSE_KEY => RC::FAIL, RC::TIMER => timer,
75
- RC::ASYNC => true, 'pipe' => wr).
76
- first.message.should.eq 'boom'
73
+ app.new.request(RC::TIMER => timer, RC::ASYNC => true, 'pipe' => wr).
74
+ message.should.eq 'boom'
77
75
  end
78
76
  end
79
77
  end
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.1
4
+ version: 3.5.2
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: 2014-12-27 00:00:00.000000000 Z
11
+ date: 2015-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httpclient