rest-core 3.4.0 → 3.4.1

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: ab6a9f5e489329946784228471a7647aac66bbdd
4
- data.tar.gz: 4b8d30e22074977305146a9a0cc875334c473599
3
+ metadata.gz: 85f12b68843aae98a2ceaa7d85346e0c99627f21
4
+ data.tar.gz: d8ba6d00b676443be83d939f7b676ad75f96ec0a
5
5
  SHA512:
6
- metadata.gz: 09378189003073e9e0fcde4b210c6ef3e5e7441388e006ba5f5e9bb916acd6b191ac7fd7e9649837dcd82e8e5d360a1efe41f3e6fa247fc9911e584b5dd074ce
7
- data.tar.gz: cdf158fd0a2ca140d64792e7daa29575c9914ca5ede20b556ef04f64bc93792f053c3d2e49f59a6888823baa623fc467dbd41edac26544b9d97057e7b511b7e2
6
+ metadata.gz: 56f4c5e7e9b54d700947e99598fa889d1bea1d2a9e07a954fcf795109bf5935263b26db50e881ad71458671213d60961b367738b400d1abe5046ade10c05d6b5
7
+ data.tar.gz: bb5712b4ac86364fcbe05ca8ad938ef6635764e73695a02a982dfb3b6028f0752539063f80ecad5ff630f75c2b185e399e60780eeeeade4938e45066b7743aa1
data/CHANGES.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # CHANGES
2
2
 
3
+ ## rest-core 3.4.1 -- 2014-11-29
4
+
5
+ ### Bugs fixed
6
+
7
+ * Handle errors for `RC::EventSource` more conservatively to avoid any
8
+ potential deadlock.
9
+
10
+ * It would not deadlock even if logging failed.
11
+
3
12
  ## rest-core 3.4.0 -- 2014-11-26
4
13
 
5
14
  ### Incompatible changes
@@ -12,12 +12,13 @@ class RestCore::EventSource < Struct.new(:client, :path, :query, :opts,
12
12
  @onmessage ||= nil
13
13
  @onerror ||= nil
14
14
  @onreconnect ||= nil
15
+ @closed ||= false
15
16
  reconnect
16
17
  self
17
18
  end
18
19
 
19
20
  def closed?
20
- !!(socket && socket.closed?)
21
+ !!(socket && socket.closed?) || @closed
21
22
  end
22
23
 
23
24
  def close
@@ -66,8 +67,11 @@ class RestCore::EventSource < Struct.new(:client, :path, :query, :opts,
66
67
  begin
67
68
  @onerror.call(error, sock) if @onerror
68
69
  onreconnect(error, sock)
69
- rescue
70
- condv.signal # so we can't be reconnecting, need to try to unblock
70
+ rescue Exception => e
71
+ mutex.synchronize do
72
+ @closed = true
73
+ condv.signal # so we can't be reconnecting, need to try to unblock
74
+ end
71
75
  raise
72
76
  end
73
77
  end
@@ -82,7 +86,10 @@ class RestCore::EventSource < Struct.new(:client, :path, :query, :opts,
82
86
  elsif closed? && @onreconnect && @onreconnect.call(error, sock)
83
87
  reconnect
84
88
  else
85
- condv.signal # we could be closing, let's try to unblock it
89
+ mutex.synchronize do
90
+ @closed = true
91
+ condv.signal # we could be closing, let's try to unblock it
92
+ end
86
93
  end
87
94
  self
88
95
  end
@@ -110,6 +117,12 @@ class RestCore::EventSource < Struct.new(:client, :path, :query, :opts,
110
117
  def reconnect
111
118
  o = {REQUEST_HEADERS => {'Accept' => 'text/event-stream'},
112
119
  HIJACK => true}.merge(opts)
113
- client.get(path, query, o){ |sock| onopen(sock) }
120
+ client.get(path, query, o) do |sock|
121
+ if sock.nil? || sock.kind_of?(Exception)
122
+ onerror(sock)
123
+ else
124
+ onopen(sock)
125
+ end
126
+ end
114
127
  end
115
128
  end
@@ -32,7 +32,11 @@ class RestCore::ErrorHandler
32
32
  def process res, err
33
33
  RC::Promise.set_backtrace(err)
34
34
  if res[ASYNC]
35
- res.merge(RESPONSE_BODY => err)
35
+ if res[HIJACK]
36
+ res.merge(RESPONSE_SOCKET => err)
37
+ else
38
+ res.merge(RESPONSE_BODY => err)
39
+ end
36
40
  else
37
41
  raise err
38
42
  end
@@ -25,6 +25,7 @@ class RestCore::Promise
25
25
  Thread.current[:backtrace] || []
26
26
  end
27
27
 
28
+ # should never raise!
28
29
  def self.set_backtrace e
29
30
  e.set_backtrace((e.backtrace || caller) + backtrace)
30
31
  end
@@ -154,18 +155,32 @@ class RestCore::Promise
154
155
  def protected_yield
155
156
  yield
156
157
  rescue Exception => e
157
- # pray if timeout won't trigger here!
158
- env[TIMER].cancel if env[TIMER]
159
158
  mutex.synchronize do
160
- self.class.set_backtrace(e)
161
- # nothing we can do here for an asynchronous exception,
162
- # so we just log the error
163
- # TODO: add error_log_method
164
- warn "RestCore: ERROR: #{e}\n from #{e.backtrace.inspect}"
165
- rejecting(e) unless done? # not done: i/o error; done: callback error
159
+ never_raise_yield do
160
+ env[TIMER].cancel if env[TIMER]
161
+ self.class.set_backtrace(e)
162
+ # TODO: add error_log_method
163
+ warn "RestCore: ERROR: #{e}\n from #{e.backtrace.inspect}"
164
+ end
165
+
166
+ begin
167
+ rejecting(e) unless done? # not done: i/o error; done: callback error
168
+ rescue Exception => e
169
+ never_raise_yield do
170
+ warn "RestCore: ERROR: #{e}\n from #{e.backtrace.inspect}"
171
+ end
172
+ end
166
173
  end
167
174
  end
168
175
 
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
179
+ yield
180
+ rescue Exception => e
181
+ Thread.main.raise(e) if !!$DEBUG
182
+ end
183
+
169
184
  # called in client thread, when yield is called
170
185
  def callback
171
186
  return response if called
@@ -41,6 +41,7 @@ class RestCore::Timer
41
41
  self.block = block
42
42
  end
43
43
 
44
+ # should never raise!
44
45
  def cancel
45
46
  timer.cancel
46
47
  self.block = nil
@@ -1,4 +1,4 @@
1
1
 
2
2
  module RestCore
3
- VERSION = '3.4.0'
3
+ VERSION = '3.4.1'
4
4
  end
@@ -1,14 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: rest-core 3.4.0 ruby lib
2
+ # stub: rest-core 3.4.1 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "rest-core"
6
- s.version = "3.4.0"
6
+ s.version = "3.4.1"
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-11-26"
11
+ s.date = "2014-11-29"
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 = [
@@ -4,6 +4,7 @@ require 'rest-core/test'
4
4
 
5
5
  describe RC::EventSource do
6
6
  after do
7
+ Muack.verify
7
8
  WebMock.reset!
8
9
  end
9
10
 
@@ -131,4 +132,34 @@ SSE
131
132
  end.start.wait
132
133
  m.should.empty?
133
134
  end
135
+
136
+ def mock_warning
137
+ mock(any_instance_of(RC::Promise)).warn(is_a(String)) do |msg|
138
+ msg.should.include?(Errno::ECONNREFUSED.new.message)
139
+ end
140
+ end
141
+
142
+ would 'not deadlock without ErrorHandler' do
143
+ mock_warning
144
+ c = RC::Simple.new.event_source('http://localhost:1')
145
+ c.onerror{ |e| e.should.eq nil }
146
+ c.start.wait
147
+ end
148
+
149
+ would 'not deadlock with ErrorHandler' do
150
+ mock_warning
151
+ c = RC::Universal.new(:log_method => false).
152
+ event_source('http://localhost:1')
153
+ c.onerror{ |e| e.should.kind_of?(Errno::ECONNREFUSED) }
154
+ c.start.wait
155
+ end
156
+
157
+ would 'not deadlock if errors in onmessage' do
158
+ err = nil
159
+ es, m, t = server.call
160
+ es.onmessage do |event, data|
161
+ raise err = "error"
162
+ end.start.wait
163
+ err.should.eq "error"
164
+ end
134
165
  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.4.0
4
+ version: 3.4.1
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-11-26 00:00:00.000000000 Z
11
+ date: 2014-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httpclient