restify 1.15.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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