restify 1.6.0 → 1.7.0

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
  SHA256:
3
- metadata.gz: 4c8ac98ab3e0dab023e3ab8d312e9c1e88a58dd13b05652097bc514a3c1e6d23
4
- data.tar.gz: eaad6494cb221afc8a3ee4175da1c754fa4cc0ca69c5fa4e12af54162672ae7b
3
+ metadata.gz: f2f418e5e5915c208da950884e753c70e0c6da648978dde9eb75f067ba6feedc
4
+ data.tar.gz: 98d1d14d29a06ac14ecaf564b0788d7054a7685ddc3126b4c24e80771ab95e86
5
5
  SHA512:
6
- metadata.gz: 6a323d105962242cc5254373f7c6481956d04dbd3cc1baada59154bcc0256e44ddae3714f184c50d99632bd4f2ceff5e16c1d27fb826c5c07f0edbfaf7e19fc7
7
- data.tar.gz: d215812e63850c400efe4339ec7ef6d770f844bf1990344a074c8811fe5c0868d92b432ad573f6ae0e2d716f48e191101c3321b889e6cf4d934bcd593fa245b0
6
+ metadata.gz: eb15fbef6af84a77badcfea901c83676952359a509e3d7a91a8b46db4d2808fd7f4c552e151d9a2b7ede68b0f46aaca5c33c77f78bd4aaa614d10a04c31862f6
7
+ data.tar.gz: 858169275d7a141d641cf1ef492692c6546057aaa6c865b1c5277038d417448b12288ac57cdc7a3e26a260b90275c6fe448deb135154ebe48dca95787ebdbf84
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.7.0
4
+
5
+ * Introduce promise dependency timeouts (#15)
6
+
3
7
  ## 1.6.0
4
8
 
5
9
  * Specify headers on restify clients and individual requests (#14)
data/lib/restify.rb CHANGED
@@ -12,6 +12,7 @@ require 'addressable/template'
12
12
  module Restify
13
13
  require 'restify/error'
14
14
  require 'restify/logging'
15
+ require 'restify/timeout'
15
16
 
16
17
  require 'restify/promise'
17
18
  require 'restify/registry'
data/lib/restify/error.rb CHANGED
@@ -3,24 +3,12 @@
3
3
  module Restify
4
4
  #
5
5
 
6
- # A {Timeout} is raised when a request or promise times out.
7
- #
8
- class Timeout < StandardError
9
- attr_reader :source
10
-
11
- def initialize(source)
12
- super "Operation with #{source.class} has timed out"
13
-
14
- @source = source
15
- end
16
- end
17
-
18
6
  # A {NetworkError} is raised on unusual network exceptions such as
19
7
  # unresolvable hosts or disconnects.
20
8
  #
21
9
  class NetworkError < StandardError
22
10
  attr_reader :request
23
-
11
+
24
12
  def initialize(request, message)
25
13
  @request = request
26
14
  super("[#{request.uri}] #{message}")
@@ -11,8 +11,13 @@ module Restify
11
11
  end
12
12
 
13
13
  def wait(timeout = nil)
14
- execute if pending?
14
+ t = Timeout.new(timeout, self)
15
+
16
+ execute(t) if pending?
17
+
15
18
  super
19
+ raise t if incomplete?
20
+ self
16
21
  end
17
22
 
18
23
  def then(&block)
@@ -26,25 +31,28 @@ module Restify
26
31
  protected
27
32
 
28
33
  # @!visibility private
29
- def ns_execute(_timeout)
34
+ def ns_execute(timeout = nil)
30
35
  return unless compare_and_set_state(:processing, :pending)
31
36
  return unless @task || @dependencies.any?
32
37
 
33
38
  executor = Concurrent::SafeTaskExecutor.new \
34
39
  method(:ns_exec), rescue_exception: true
35
40
 
36
- success, value, reason = executor.execute
41
+ success, value, reason = executor.execute(timeout)
37
42
 
38
43
  complete success, value, reason
39
44
  end
40
45
 
41
46
  # @!visibility private
42
- def ns_exec
43
- args = @dependencies.any? ? @dependencies.map(&:value!) : []
44
- value = @task ? @task.call(*args) : args
47
+ def ns_exec(timeout = nil)
48
+ t = Timeout.new(timeout, self)
45
49
 
46
- value = value.value! while value.is_a? Restify::Promise
50
+ args = @dependencies.map do |d|
51
+ t.wait_on!(d)
52
+ end
47
53
 
54
+ value = @task ? @task.call(*args) : args
55
+ value = t.wait_on!(value) while value.is_a?(Promise)
48
56
  value
49
57
  end
50
58
 
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'hitimes'
4
+
5
+ module Restify
6
+ class Timeout
7
+ class << self
8
+ attr_accessor :default_timeout
9
+ end
10
+
11
+ # Default wait timeout of 300 seconds.
12
+ self.default_timeout = 300
13
+
14
+ def initialize(timeout, target = nil)
15
+ @timeout = parse_timeout(timeout)
16
+ @target = target
17
+
18
+ @interval = ::Hitimes::Interval.new
19
+ @interval.start
20
+ end
21
+
22
+ def wait_on!(ivar)
23
+ ivar.value!(wait_interval).tap do
24
+ raise self unless ivar.complete?
25
+ end
26
+ rescue ::Timeout::Error
27
+ raise self
28
+ end
29
+
30
+ def timeout!
31
+ raise self if wait_interval <= 0
32
+ end
33
+
34
+ def exception
35
+ Error.new(@target)
36
+ end
37
+
38
+ private
39
+
40
+ def wait_interval
41
+ @timeout - @interval.to_f
42
+ end
43
+
44
+ def parse_timeout(value)
45
+ return self.class.default_timeout if value.nil?
46
+
47
+ begin
48
+ value = Float(value)
49
+ rescue ArgumentError
50
+ raise ArgumentError.new \
51
+ "Timeout must be an number but is #{value}"
52
+ end
53
+
54
+ unless value > 0
55
+ raise ArgumentError.new "Timeout must be > 0 but is #{value.inspect}."
56
+ end
57
+
58
+ value
59
+ end
60
+
61
+ class << self
62
+ def new(timeout, *args)
63
+ return timeout if timeout.is_a?(self)
64
+ super
65
+ end
66
+ end
67
+
68
+ class Error < ::Timeout::Error
69
+ attr_reader :target
70
+
71
+ def initialize(target)
72
+ @target = target
73
+
74
+ if @target
75
+ super "Operation on #{@target} timed out"
76
+ else
77
+ super 'Operation timed out'
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -3,7 +3,7 @@
3
3
  module Restify
4
4
  module VERSION
5
5
  MAJOR = 1
6
- MINOR = 6
6
+ MINOR = 7
7
7
  PATCH = 0
8
8
  STAGE = nil
9
9
  STRING = [MAJOR, MINOR, PATCH, STAGE].reject(&:nil?).join('.').freeze
@@ -3,6 +3,8 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Restify::Promise do
6
+ let(:promise) { described_class.new }
7
+
6
8
  describe 'factory methods' do
7
9
  describe '#fulfilled' do
8
10
  subject { described_class.fulfilled(fulfill_value) }
@@ -162,4 +164,22 @@ describe Restify::Promise do
162
164
  end
163
165
  end
164
166
  end
167
+
168
+ describe '#wait' do
169
+ it 'can time out' do
170
+ expect { promise.wait(0.1) }.to raise_error ::Timeout::Error
171
+ end
172
+ end
173
+
174
+ describe '#value' do
175
+ it 'can time out' do
176
+ expect { promise.value!(0.1) }.to raise_error ::Timeout::Error
177
+ end
178
+ end
179
+
180
+ describe '#value!' do
181
+ it 'can time out' do
182
+ expect { promise.value!(0.1) }.to raise_error ::Timeout::Error
183
+ end
184
+ end
165
185
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Restify::Timeout do
6
+ let(:timer) { described_class.new(0.2) }
7
+
8
+ describe '#timeout!' do
9
+ context 'before having timed out' do
10
+ it 'do nothing' do
11
+ expect { timer.timeout! }.to_not raise_error
12
+ end
13
+ end
14
+
15
+ context 'after having timed out' do
16
+ it 'calls given block' do
17
+ expect { timer.timeout! }.to_not raise_error
18
+ sleep timer.send(:wait_interval)
19
+ expect { timer.timeout! }.to raise_error ::Restify::Timeout::Error
20
+ end
21
+ end
22
+ end
23
+
24
+ describe '#wait_on!' do
25
+ it 'calls block on IVar timeout' do
26
+ expect {
27
+ timer.wait_on!(Concurrent::IVar.new)
28
+ }.to raise_error ::Restify::Timeout::Error
29
+ end
30
+
31
+ it 'calls block on Promise timeout' do
32
+ expect {
33
+ timer.wait_on!(Restify::Promise.new)
34
+ }.to raise_error ::Restify::Timeout::Error
35
+ end
36
+
37
+ it 'does nothing on successful IVar' do
38
+ expect {
39
+ Concurrent::IVar.new.tap do |ivar|
40
+ Thread.new { ivar.set :success }
41
+ expect(timer.wait_on!(ivar)).to eq :success
42
+ end
43
+ }.to_not raise_error
44
+ end
45
+
46
+ it 'does nothing on successful Promise' do
47
+ expect {
48
+ Restify::Promise.fulfilled(:success).tap do |p|
49
+ expect(timer.wait_on!(p)).to eq :success
50
+ end
51
+ }.to_not raise_error
52
+ end
53
+ end
54
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restify
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Graichen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-09 00:00:00.000000000 Z
11
+ date: 2018-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: '1.2'
125
+ - !ruby/object:Gem::Dependency
126
+ name: hitimes
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: bundler
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -168,6 +182,7 @@ files:
168
182
  - lib/restify/request.rb
169
183
  - lib/restify/resource.rb
170
184
  - lib/restify/response.rb
185
+ - lib/restify/timeout.rb
171
186
  - lib/restify/version.rb
172
187
  - spec/restify/cache_spec.rb
173
188
  - spec/restify/context_spec.rb
@@ -181,6 +196,7 @@ files:
181
196
  - spec/restify/registry_spec.rb
182
197
  - spec/restify/relation_spec.rb
183
198
  - spec/restify/resource_spec.rb
199
+ - spec/restify/timeout_spec.rb
184
200
  - spec/restify_spec.rb
185
201
  - spec/spec_helper.rb
186
202
  homepage: https://github.com/jgraichen/restify
@@ -220,5 +236,6 @@ test_files:
220
236
  - spec/restify/registry_spec.rb
221
237
  - spec/restify/relation_spec.rb
222
238
  - spec/restify/resource_spec.rb
239
+ - spec/restify/timeout_spec.rb
223
240
  - spec/restify_spec.rb
224
241
  - spec/spec_helper.rb