restify 1.15.2 → 2.0.1

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