rest-core 3.5.1 → 3.5.2

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.
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