restify 1.15.1 → 2.0.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +102 -15
  3. data/README.md +23 -31
  4. data/lib/restify/adapter/base.rb +4 -0
  5. data/lib/restify/adapter/telemetry.rb +54 -0
  6. data/lib/restify/adapter/typhoeus.rb +24 -14
  7. data/lib/restify/context.rb +7 -11
  8. data/lib/restify/error.rb +2 -2
  9. data/lib/restify/global.rb +1 -0
  10. data/lib/restify/link.rb +4 -4
  11. data/lib/restify/logging.rb +1 -1
  12. data/lib/restify/processors/base/parsing.rb +5 -24
  13. data/lib/restify/processors/base.rb +1 -1
  14. data/lib/restify/promise.rb +2 -2
  15. data/lib/restify/registry.rb +1 -1
  16. data/lib/restify/relation.rb +45 -17
  17. data/lib/restify/request.rb +6 -6
  18. data/lib/restify/resource.rb +1 -1
  19. data/lib/restify/response.rb +0 -2
  20. data/lib/restify/timeout.rb +2 -2
  21. data/lib/restify/version.rb +4 -4
  22. data/lib/restify.rb +0 -1
  23. data/spec/restify/cache_spec.rb +16 -12
  24. data/spec/restify/context_spec.rb +15 -7
  25. data/spec/restify/error_spec.rb +23 -16
  26. data/spec/restify/features/head_requests_spec.rb +7 -5
  27. data/spec/restify/features/request_bodies_spec.rb +14 -13
  28. data/spec/restify/features/request_errors_spec.rb +2 -2
  29. data/spec/restify/features/request_headers_spec.rb +11 -14
  30. data/spec/restify/features/response_errors_spec.rb +2 -2
  31. data/spec/restify/global_spec.rb +13 -13
  32. data/spec/restify/link_spec.rb +9 -9
  33. data/spec/restify/processors/base_spec.rb +7 -7
  34. data/spec/restify/processors/json_spec.rb +22 -62
  35. data/spec/restify/processors/msgpack_spec.rb +40 -76
  36. data/spec/restify/promise_spec.rb +38 -34
  37. data/spec/restify/registry_spec.rb +6 -8
  38. data/spec/restify/relation_spec.rb +196 -17
  39. data/spec/restify/resource_spec.rb +55 -60
  40. data/spec/restify/timeout_spec.rb +7 -7
  41. data/spec/restify_spec.rb +13 -74
  42. data/spec/spec_helper.rb +13 -17
  43. data/spec/support/stub_server.rb +3 -3
  44. metadata +35 -65
  45. data/lib/restify/adapter/em.rb +0 -139
  46. data/lib/restify/adapter/pooled_em.rb +0 -270
@@ -1,270 +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
- @pool = Pool.new(**kwargs)
201
- end
202
-
203
- # rubocop:disable Metrics/MethodLength
204
- # rubocop:disable Metrics/AbcSize
205
- # rubocop:disable Metrics/BlockLength
206
- def call_native(request, writer)
207
- next_tick do
208
- defer = @pool.get(request)
209
-
210
- defer.errback do |error|
211
- writer.reject(error)
212
- end
213
-
214
- defer.callback do |conn|
215
- req = conn.send request.method.downcase,
216
- keepalive: true,
217
- redirects: 3,
218
- path: request.uri.normalized_path,
219
- query: request.uri.normalized_query,
220
- body: request.body,
221
- head: request.headers
222
-
223
- req.callback do
224
- writer.fulfill Response.new(
225
- request,
226
- req.last_effective_url,
227
- req.response_header.status,
228
- req.response_header,
229
- req.response
230
- )
231
-
232
- if req.response_header['CONNECTION'] == 'close'
233
- @pool.remove(conn)
234
- else
235
- @pool << conn
236
- end
237
- end
238
-
239
- req.errback do
240
- @pool.remove(conn)
241
- writer.reject(req.error)
242
- end
243
- rescue Exception => e # rubocop:disable Lint/RescueException
244
- @pool.remove(conn)
245
- writer.reject(e)
246
- end
247
- end
248
- end
249
- # rubocop:enable all
250
-
251
- private
252
-
253
- def next_tick(&block)
254
- ensure_running
255
- EventMachine.next_tick(&block)
256
- end
257
-
258
- def ensure_running
259
- return if EventMachine.reactor_running?
260
-
261
- Thread.new do
262
- EventMachine.run {}
263
- rescue StandardError => e
264
- logger.error(e)
265
- raise e
266
- end
267
- end
268
- end
269
- end
270
- end