restify 1.6.0 → 1.7.0

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