restify 1.15.2 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -2
  3. data/README.md +23 -31
  4. data/doc/file.README.html +192 -0
  5. data/lib/restify/adapter/base.rb +4 -0
  6. data/lib/restify/adapter/telemetry.rb +54 -0
  7. data/lib/restify/adapter/typhoeus.rb +37 -4
  8. data/lib/restify/context.rb +3 -3
  9. data/lib/restify/error.rb +2 -2
  10. data/lib/restify/link.rb +4 -4
  11. data/lib/restify/processors/base/parsing.rb +2 -21
  12. data/lib/restify/processors/base.rb +1 -1
  13. data/lib/restify/promise.rb +2 -2
  14. data/lib/restify/registry.rb +1 -1
  15. data/lib/restify/relation.rb +45 -17
  16. data/lib/restify/request.rb +6 -6
  17. data/lib/restify/timeout.rb +2 -2
  18. data/lib/restify/version.rb +3 -3
  19. data/lib/restify.rb +0 -1
  20. data/spec/restify/cache_spec.rb +16 -12
  21. data/spec/restify/context_spec.rb +8 -3
  22. data/spec/restify/error_spec.rb +13 -16
  23. data/spec/restify/features/head_requests_spec.rb +5 -4
  24. data/spec/restify/features/opentelemetry_spec.rb +46 -0
  25. data/spec/restify/features/request_bodies_spec.rb +8 -8
  26. data/spec/restify/features/request_errors_spec.rb +2 -2
  27. data/spec/restify/features/request_headers_spec.rb +3 -6
  28. data/spec/restify/features/response_errors_spec.rb +1 -1
  29. data/spec/restify/features/webmock_spec.rb +27 -0
  30. data/spec/restify/global_spec.rb +10 -10
  31. data/spec/restify/processors/base_spec.rb +6 -7
  32. data/spec/restify/processors/json_spec.rb +21 -62
  33. data/spec/restify/processors/msgpack_spec.rb +33 -70
  34. data/spec/restify/promise_spec.rb +31 -31
  35. data/spec/restify/registry_spec.rb +5 -7
  36. data/spec/restify/relation_spec.rb +185 -7
  37. data/spec/restify/resource_spec.rb +47 -53
  38. data/spec/restify/timeout_spec.rb +3 -3
  39. data/spec/restify_spec.rb +12 -73
  40. data/spec/spec_helper.rb +12 -15
  41. data/spec/support/opentelemetry.rb +29 -0
  42. data/spec/support/stub_server.rb +4 -0
  43. metadata +37 -64
  44. data/lib/restify/adapter/em.rb +0 -134
  45. data/lib/restify/adapter/pooled_em.rb +0 -269
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restify
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.15.2
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Graichen
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2021-12-23 00:00:00.000000000 Z
10
+ date: 2025-02-16 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activesupport
@@ -52,26 +51,6 @@ dependencies:
52
51
  - - "~>"
53
52
  - !ruby/object:Gem::Version
54
53
  version: '1.0'
55
- - !ruby/object:Gem::Dependency
56
- name: hashie
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '3.3'
62
- - - "<"
63
- - !ruby/object:Gem::Version
64
- version: '5.0'
65
- type: :runtime
66
- prerelease: false
67
- version_requirements: !ruby/object:Gem::Requirement
68
- requirements:
69
- - - ">="
70
- - !ruby/object:Gem::Version
71
- version: '3.3'
72
- - - "<"
73
- - !ruby/object:Gem::Version
74
- version: '5.0'
75
54
  - !ruby/object:Gem::Dependency
76
55
  name: hitimes
77
56
  requirement: !ruby/object:Gem::Requirement
@@ -115,51 +94,65 @@ dependencies:
115
94
  - !ruby/object:Gem::Version
116
95
  version: '1.2'
117
96
  - !ruby/object:Gem::Dependency
118
- name: rack
97
+ name: opentelemetry-api
119
98
  requirement: !ruby/object:Gem::Requirement
120
99
  requirements:
121
- - - ">="
100
+ - - "~>"
122
101
  - !ruby/object:Gem::Version
123
- version: '0'
102
+ version: '1.0'
124
103
  type: :runtime
125
104
  prerelease: false
126
105
  version_requirements: !ruby/object:Gem::Requirement
127
106
  requirements:
128
- - - ">="
107
+ - - "~>"
129
108
  - !ruby/object:Gem::Version
130
- version: '0'
109
+ version: '1.0'
131
110
  - !ruby/object:Gem::Dependency
132
- name: typhoeus
111
+ name: opentelemetry-common
133
112
  requirement: !ruby/object:Gem::Requirement
134
113
  requirements:
135
- - - "~>"
114
+ - - ">="
136
115
  - !ruby/object:Gem::Version
137
- version: '1.3'
116
+ version: '0'
138
117
  type: :runtime
139
118
  prerelease: false
140
119
  version_requirements: !ruby/object:Gem::Requirement
141
120
  requirements:
142
- - - "~>"
121
+ - - ">="
143
122
  - !ruby/object:Gem::Version
144
- version: '1.3'
123
+ version: '0'
145
124
  - !ruby/object:Gem::Dependency
146
- name: bundler
125
+ name: rack
147
126
  requirement: !ruby/object:Gem::Requirement
148
127
  requirements:
149
128
  - - ">="
150
129
  - !ruby/object:Gem::Version
151
130
  version: '0'
152
- type: :development
131
+ type: :runtime
153
132
  prerelease: false
154
133
  version_requirements: !ruby/object:Gem::Requirement
155
134
  requirements:
156
135
  - - ">="
157
136
  - !ruby/object:Gem::Version
158
137
  version: '0'
138
+ - !ruby/object:Gem::Dependency
139
+ name: typhoeus
140
+ requirement: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '1.3'
145
+ type: :runtime
146
+ prerelease: false
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '1.3'
159
152
  description: An experimental hypermedia REST client that uses parallel, keep-alive
160
153
  and pipelined requests by default.
161
154
  email:
162
- - jg@altimos.de
155
+ - jgraichen@altimos.de
163
156
  executables: []
164
157
  extensions: []
165
158
  extra_rdoc_files: []
@@ -167,10 +160,10 @@ files:
167
160
  - CHANGELOG.md
168
161
  - LICENSE.txt
169
162
  - README.md
163
+ - doc/file.README.html
170
164
  - lib/restify.rb
171
165
  - lib/restify/adapter/base.rb
172
- - lib/restify/adapter/em.rb
173
- - lib/restify/adapter/pooled_em.rb
166
+ - lib/restify/adapter/telemetry.rb
174
167
  - lib/restify/adapter/typhoeus.rb
175
168
  - lib/restify/cache.rb
176
169
  - lib/restify/context.rb
@@ -194,10 +187,12 @@ files:
194
187
  - spec/restify/context_spec.rb
195
188
  - spec/restify/error_spec.rb
196
189
  - spec/restify/features/head_requests_spec.rb
190
+ - spec/restify/features/opentelemetry_spec.rb
197
191
  - spec/restify/features/request_bodies_spec.rb
198
192
  - spec/restify/features/request_errors_spec.rb
199
193
  - spec/restify/features/request_headers_spec.rb
200
194
  - spec/restify/features/response_errors_spec.rb
195
+ - spec/restify/features/webmock_spec.rb
201
196
  - spec/restify/global_spec.rb
202
197
  - spec/restify/link_spec.rb
203
198
  - spec/restify/processors/base_spec.rb
@@ -210,13 +205,13 @@ files:
210
205
  - spec/restify/timeout_spec.rb
211
206
  - spec/restify_spec.rb
212
207
  - spec/spec_helper.rb
208
+ - spec/support/opentelemetry.rb
213
209
  - spec/support/stub_server.rb
214
210
  homepage: https://github.com/jgraichen/restify
215
211
  licenses:
216
212
  - LGPL-3.0+
217
213
  metadata:
218
214
  rubygems_mfa_required: 'true'
219
- post_install_message:
220
215
  rdoc_options: []
221
216
  require_paths:
222
217
  - lib
@@ -224,36 +219,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
224
219
  requirements:
225
220
  - - ">="
226
221
  - !ruby/object:Gem::Version
227
- version: 2.5.0
222
+ version: 3.1.0
228
223
  required_rubygems_version: !ruby/object:Gem::Requirement
229
224
  requirements:
230
225
  - - ">="
231
226
  - !ruby/object:Gem::Version
232
227
  version: '0'
233
228
  requirements: []
234
- rubygems_version: 3.1.6
235
- signing_key:
229
+ rubygems_version: 3.6.2
236
230
  specification_version: 4
237
231
  summary: An experimental hypermedia REST client.
238
- test_files:
239
- - spec/restify/cache_spec.rb
240
- - spec/restify/context_spec.rb
241
- - spec/restify/error_spec.rb
242
- - spec/restify/features/head_requests_spec.rb
243
- - spec/restify/features/request_bodies_spec.rb
244
- - spec/restify/features/request_errors_spec.rb
245
- - spec/restify/features/request_headers_spec.rb
246
- - spec/restify/features/response_errors_spec.rb
247
- - spec/restify/global_spec.rb
248
- - spec/restify/link_spec.rb
249
- - spec/restify/processors/base_spec.rb
250
- - spec/restify/processors/json_spec.rb
251
- - spec/restify/processors/msgpack_spec.rb
252
- - spec/restify/promise_spec.rb
253
- - spec/restify/registry_spec.rb
254
- - spec/restify/relation_spec.rb
255
- - spec/restify/resource_spec.rb
256
- - spec/restify/timeout_spec.rb
257
- - spec/restify_spec.rb
258
- - spec/spec_helper.rb
259
- - spec/support/stub_server.rb
232
+ test_files: []
@@ -1,134 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'eventmachine'
4
- require 'em-http-request'
5
-
6
- module Restify
7
- module Adapter
8
- class EM < Base
9
- class Connection
10
- class << self
11
- def open(uri)
12
- connections[uri.origin] ||= new uri.origin
13
- end
14
-
15
- def connections
16
- @connections ||= {}
17
- end
18
- end
19
-
20
- attr_reader :origin
21
-
22
- def initialize(origin)
23
- @origin = origin
24
- @pipeline = true
25
- end
26
-
27
- def requests
28
- @requests ||= []
29
- end
30
-
31
- # rubocop:disable Style/IdenticalConditionalBranches
32
- def call(request, writer, retried: false)
33
- if requests.empty?
34
- requests << [request, writer, retried]
35
- process_next
36
- else
37
- requests << [request, writer, retried]
38
- end
39
- end
40
- # rubocop:enable all
41
-
42
- def connection
43
- @connection ||= EventMachine::HttpRequest.new(origin)
44
- end
45
-
46
- def pipeline?
47
- @pipeline
48
- end
49
-
50
- def process_next
51
- return if requests.empty?
52
-
53
- request, writer, retried = pipeline? ? requests.shift : requests.first
54
- begin
55
- req = connection.send request.method.downcase,
56
- keepalive: true,
57
- redirects: 3,
58
- path: request.uri.normalized_path,
59
- query: request.uri.normalized_query,
60
- body: request.body,
61
- head: request.headers
62
- rescue Exception => e # rubocop:disable Lint/RescueException
63
- writer.reject e
64
- requests.shift unless pipeline?
65
- return
66
- end
67
-
68
- req.callback do
69
- requests.shift unless pipeline?
70
-
71
- writer.fulfill Response.new(
72
- request,
73
- req.last_effective_url,
74
- req.response_header.status,
75
- req.response_header,
76
- req.response,
77
- )
78
-
79
- if req.response_header['CONNECTION'] == 'close'
80
- @connection = nil
81
- @pipeline = false
82
- end
83
-
84
- process_next
85
- end
86
-
87
- req.errback do
88
- requests.shift unless pipeline?
89
- @connection = nil
90
-
91
- if pipeline?
92
- EventMachine.next_tick do
93
- @pipeline = false
94
- call request, writer
95
- end
96
- elsif !retried
97
- EventMachine.next_tick { call request, writer }
98
- else
99
- begin
100
- raise "(#{req.response_header.status}) #{req.error}"
101
- rescue StandardError => e
102
- writer.reject e
103
- end
104
- end
105
- end
106
- end
107
- end
108
-
109
- def call_native(request, writer)
110
- next_tick do
111
- Connection.open(request.uri).call(request, writer)
112
- end
113
- end
114
-
115
- private
116
-
117
- def next_tick(&block)
118
- ensure_running
119
- EventMachine.next_tick(&block)
120
- end
121
-
122
- def ensure_running
123
- return if EventMachine.reactor_running?
124
-
125
- Thread.new do
126
- EventMachine.run
127
- rescue StandardError => e
128
- puts "#{self.class} -> #{e}\n#{e.backtrace.join("\n")}"
129
- raise e
130
- end
131
- end
132
- end
133
- end
134
- end
@@ -1,269 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'eventmachine'
4
- require 'em-http-request'
5
-
6
- module Restify
7
- module Adapter
8
- class PooledEM < Base
9
- include Logging
10
-
11
- # This class maintains a pool of connection objects, grouped by origin,
12
- # and ensures limits for total parallel requests and per-origin requests.
13
- #
14
- # It does so by maintaining a list of already open, reusable connections.
15
- # When any of them are checked out for usage, it counts the usages to
16
- # prevent constraints being broken.
17
- class Pool
18
- include Logging
19
-
20
- def initialize(size: 32, per_host: 6, connect_timeout: 2, inactivity_timeout: 10)
21
- @size = size
22
- @per_host = per_host
23
- @connect_timeout = connect_timeout
24
- @inactivity_timeout = inactivity_timeout
25
-
26
- @host = Hash.new {|h, k| h[k] = 0 }
27
- @available = []
28
- @queue = []
29
- @used = 0
30
- end
31
-
32
- # Request a connection from the pool.
33
- #
34
- # Attempts to checkout a reusable connection from the pool (or create a
35
- # new one). If any of the limits have been reached, the request will be
36
- # put onto a queue until other connections are released.
37
- #
38
- # Returns a Deferrable that succeeds with a connection instance once a
39
- # connection has been checked out (usually immediately).
40
- #
41
- # @return [Deferrable<Request>]
42
- #
43
- def get(request, timeout: 2)
44
- defer = Deferrable.new(request)
45
- defer.timeout(timeout, :timeout)
46
- defer.errback { @queue.delete(defer) }
47
-
48
- checkout(defer)
49
-
50
- defer
51
- end
52
-
53
- # Return a connection to the pool.
54
- #
55
- # If there are requests in the queue (due to one of the limits having
56
- # been reached), they will be given an attempt to use the released
57
- # connection.
58
- #
59
- # If no requests are queued, the connection will be held for reuse by a
60
- # subsequent request.
61
- #
62
- # @return [void]
63
- #
64
- def release(conn)
65
- @available.unshift(conn) if @available.size < @size
66
- @used -= 1 if @used.positive?
67
-
68
- logger.debug do
69
- "[#{conn.uri}] Released to pool (#{@available.size}/#{@used}/#{size})"
70
- end
71
-
72
- checkout(@queue.shift) if @queue.any? # checkout next waiting defer
73
- end
74
-
75
- alias << release
76
-
77
- def remove(conn)
78
- close(conn)
79
-
80
- logger.debug do
81
- "[#{conn.uri}] Removed from pool (#{@available.size}/#{@used}/#{size})"
82
- end
83
-
84
- checkout(@queue.shift) if @queue.any? # checkout next waiting defer
85
- end
86
-
87
- # Determine the number of connections in the pool.
88
- #
89
- # This takes into account both reusable (idle) and used connections.
90
- #
91
- # @return [Integer]
92
- #
93
- def size
94
- @available.size + @used
95
- end
96
-
97
- private
98
-
99
- def close(conn)
100
- @used -= 1 if @used.positive?
101
- @host[conn.uri.to_s] -= 1
102
-
103
- conn.close
104
- end
105
-
106
- def checkout(defer)
107
- origin = defer.request.uri.origin
108
-
109
- if (index = find_reusable_connection(origin))
110
- defer.succeed reuse_connection(index, origin)
111
- elsif can_build_new_connection?(origin)
112
- defer.succeed new_connection(origin)
113
- else
114
- queue defer
115
- end
116
- end
117
-
118
- def find_reusable_connection(origin)
119
- @available.find_index {|conn| conn.uri == origin }
120
- end
121
-
122
- def reuse_connection(index, origin)
123
- @used += 1
124
- @available.delete_at(index).tap do
125
- logger.debug do
126
- "[#{origin}] Take connection from pool " \
127
- "(#{@available.size}/#{@used}/#{size})"
128
- end
129
- end
130
- end
131
-
132
- def new_connection(origin)
133
- # If we have reached the limit, we have to throw away the oldest
134
- # reusable connection in order to open a new one
135
- close_oldest if size >= @size
136
-
137
- @used += 1
138
- new(origin).tap do
139
- logger.debug do
140
- "[#{origin}] Add new connection to pool " \
141
- "(#{@available.size}/#{@used}/#{size})"
142
- end
143
- end
144
- end
145
-
146
- def close_oldest
147
- close(@available.pop)
148
-
149
- logger.debug do
150
- "[#{origin}] Closed oldest connection in pool " \
151
- "(#{@available.size}/#{@used}/#{size})"
152
- end
153
- end
154
-
155
- def queue(defer)
156
- logger.debug do
157
- "[#{origin}] Wait for free slot " \
158
- "(#{@available.size}/#{@used}/#{size})"
159
- end
160
-
161
- @queue << defer
162
- end
163
-
164
- def new(origin)
165
- logger.debug do
166
- "Connect to '#{origin}' " \
167
- "(#{@connect_timeout}/#{@inactivity_timeout})..."
168
- end
169
-
170
- @host[origin] += 1
171
-
172
- EventMachine::HttpRequest.new origin,
173
- connect_timeout: @connect_timeout,
174
- inactivity_timeout: @inactivity_timeout
175
- end
176
-
177
- def can_build_new_connection?(origin)
178
- return false if @host[origin] >= @per_host
179
-
180
- size < @size || @available.any?
181
- end
182
-
183
- class Deferrable
184
- include ::EventMachine::Deferrable
185
-
186
- attr_reader :request
187
-
188
- def initialize(request)
189
- @request = request
190
- end
191
-
192
- def succeed(connection)
193
- @connection = connection
194
- super
195
- end
196
- end
197
- end
198
-
199
- def initialize(**kwargs)
200
- super()
201
- @pool = Pool.new(**kwargs)
202
- end
203
-
204
- # rubocop:disable Metrics/BlockLength
205
- def call_native(request, writer)
206
- next_tick do
207
- defer = @pool.get(request)
208
-
209
- defer.errback do |error|
210
- writer.reject(error)
211
- end
212
-
213
- defer.callback do |conn|
214
- req = conn.send request.method.downcase,
215
- keepalive: true,
216
- redirects: 3,
217
- path: request.uri.normalized_path,
218
- query: request.uri.normalized_query,
219
- body: request.body,
220
- head: request.headers
221
-
222
- req.callback do
223
- writer.fulfill Response.new(
224
- request,
225
- req.last_effective_url,
226
- req.response_header.status,
227
- req.response_header,
228
- req.response,
229
- )
230
-
231
- if req.response_header['CONNECTION'] == 'close'
232
- @pool.remove(conn)
233
- else
234
- @pool << conn
235
- end
236
- end
237
-
238
- req.errback do
239
- @pool.remove(conn)
240
- writer.reject(req.error)
241
- end
242
- rescue Exception => e # rubocop:disable Lint/RescueException
243
- @pool.remove(conn)
244
- writer.reject(e)
245
- end
246
- end
247
- end
248
- # rubocop:enable all
249
-
250
- private
251
-
252
- def next_tick(&block)
253
- ensure_running
254
- EventMachine.next_tick(&block)
255
- end
256
-
257
- def ensure_running
258
- return if EventMachine.reactor_running?
259
-
260
- Thread.new do
261
- EventMachine.run
262
- rescue StandardError => e
263
- logger.error(e)
264
- raise e
265
- end
266
- end
267
- end
268
- end
269
- end