google-gax 0.1.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4c5ff2bfbcc82e5320ab20d550923bdf003c4a7a
4
- data.tar.gz: 83336c0d592b0ccfe965bc6d667ce4497ea6fbb1
3
+ metadata.gz: df878307196d3628c155d4de6d3b333524b93937
4
+ data.tar.gz: bd5b46d05109352ad29de368998e36efe1bfcd8d
5
5
  SHA512:
6
- metadata.gz: d68e2841381b5ec2d8d9c4ec9f189e8c78cb9306ac4df3444133f1dc8bccc7e94faf213d47068fad5025377c33e271be2d6f6a1130c494e82eb69b79aa848244
7
- data.tar.gz: b58732d2fc4a3d45fc70cc9b59a0ecd3975f385ef6062749cbc483596601c566359f5937f08c8916f47f4341683587402fa2cc9647b282e24931b14fdf22304a
6
+ metadata.gz: 18285c95727f2da714caf8c9ad7d8a99cb7d50bfeb2322045dbc4f4bf4f1b549441d7f0b8e035ab9d708fd820ebc9252260ec17165a90fb36d681f7fecc1e007
7
+ data.tar.gz: 50b8a13d7f050e099146eba2f1d11f77e123c5fa64923d731d3707ff2f539e70d71a9f6dea790143990fa47e05b801e8501cd5d3ca0b51f4291e07368e15ab7a
@@ -36,6 +36,8 @@ require 'google/gax/version'
36
36
 
37
37
  module Google
38
38
  module Gax
39
+ # rubocop:disable Metrics/ParameterLists
40
+
39
41
  # Encapsulates the call settings for an ApiCallable
40
42
  # @!attribute [r] timeout
41
43
  # @return [Numeric]
@@ -43,29 +45,34 @@ module Google
43
45
  # @return [RetryOptions]
44
46
  # @!attribute [r] page_descriptor
45
47
  # @return [PageDescriptor]
48
+ # @!attribute [r] page_token
49
+ # @return [Object]
46
50
  # @!attribute [r] bundle_descriptor
47
51
  # @return [BundleDescriptor]
48
52
  class CallSettings
49
- attr_reader :timeout, :retry_options, :page_descriptor, :bundler,
50
- :bundle_descriptor
53
+ attr_reader :timeout, :retry_options, :page_descriptor, :page_token,
54
+ :bundler, :bundle_descriptor
51
55
 
52
56
  # @param timeout [Numeric] The client-side timeout for API calls. This
53
57
  # parameter is ignored for retrying calls.
54
58
  # @param retry_options [RetryOptions] The configuration for retrying upon
55
- # transient error. If set to None, this call will not retry.
59
+ # transient error. If set to nil, this call will not retry.
56
60
  # @param page_descriptor [PageDescriptor] indicates the structure of page
57
- # streaming to be performed. If set to None, page streaming is not
61
+ # streaming to be performed. If set to nil, page streaming is not
58
62
  # performed.
59
- # @param bundler orchestrates bundling. If None, bundling is not
63
+ # @param page_token [Object] determines the page token used in the
64
+ # page streaming request. If there is no page_descriptor, this has no
65
+ # meaning.
66
+ # @param bundler orchestrates bundling. If nil, bundling is not
60
67
  # performed.
61
68
  # @param bundle_descriptor [BundleDescriptor] indicates the structure of
62
- # the bundle. If None, bundling is not performed.
63
- def initialize(
64
- timeout: 30, retry_options: nil, page_descriptor: nil,
65
- bundler: nil, bundle_descriptor: nil)
69
+ # the bundle. If nil, bundling is not performed.
70
+ def initialize(timeout: 30, retry_options: nil, page_descriptor: nil,
71
+ page_token: nil, bundler: nil, bundle_descriptor: nil)
66
72
  @timeout = timeout
67
73
  @retry_options = retry_options
68
74
  @page_descriptor = page_descriptor
75
+ @page_token = page_token
69
76
  @bundler = bundler
70
77
  @bundle_descriptor = bundle_descriptor
71
78
  end
@@ -86,12 +93,12 @@ module Google
86
93
  # @return a new merged call settings.
87
94
  def merge(options)
88
95
  unless options
89
- return CallSettings.new(
90
- timeout: @timeout,
91
- retry_options: @retry_options,
92
- page_descriptor: @page_descriptor,
93
- bundler: @bundler,
94
- bundle_descriptor: @bundle_descriptor)
96
+ return CallSettings.new(timeout: @timeout,
97
+ retry_options: @retry_options,
98
+ page_descriptor: @page_descriptor,
99
+ page_token: @page_token,
100
+ bundler: @bundler,
101
+ bundle_descriptor: @bundle_descriptor)
95
102
  end
96
103
 
97
104
  timeout = if options.timeout == :OPTION_INHERIT
@@ -104,14 +111,18 @@ module Google
104
111
  else
105
112
  options.retry_options
106
113
  end
107
- page_descriptor = @page_descriptor if options.is_page_streaming
114
+ page_token = if options.page_token == :OPTION_INHERIT
115
+ @page_token
116
+ else
117
+ options.page_token
118
+ end
108
119
 
109
- CallSettings.new(
110
- timeout: timeout,
111
- retry_options: retry_options,
112
- page_descriptor: page_descriptor,
113
- bundler: @bundler,
114
- bundle_descriptor: @bundle_descriptor)
120
+ CallSettings.new(timeout: timeout,
121
+ retry_options: retry_options,
122
+ page_descriptor: @page_descriptor,
123
+ page_token: page_token,
124
+ bundler: @bundler,
125
+ bundle_descriptor: @bundle_descriptor)
115
126
  end
116
127
  end
117
128
 
@@ -120,34 +131,32 @@ module Google
120
131
  # @return [Numeric, :OPTION_INHERIT]
121
132
  # @!attribute [r] retry_options
122
133
  # @return [RetryOptions, :OPTION_INHERIT]
123
- # @!attribute [r] is_page_streaming
124
- # @return [true, false, :OPTION_INHERIT]
134
+ # @!attribute [r] page_token
135
+ # @return [Object, :OPTION_INHERIT, :INITIAL_PAGE]
125
136
  class CallOptions
126
- attr_reader :timeout, :retry_options, :is_page_streaming
137
+ attr_reader :timeout, :retry_options, :page_token
127
138
 
128
139
  # @param timeout [Numeric, :OPTION_INHERIT]
129
140
  # The client-side timeout for API calls.
130
141
  # @param retry_options [RetryOptions, :OPTION_INHERIT]
131
142
  # The configuration for retrying upon transient error.
132
143
  # If set to nil, this call will not retry.
133
- # @param is_page_streaming [true, false, :OPTION_INHERIT]
144
+ # @param page_token [Object, :OPTION_INHERIT]
134
145
  # If set and the call is configured for page streaming, page streaming
135
- # is performed.
136
- def initialize(
137
- timeout: :OPTION_INHERIT,
138
- retry_options: :OPTION_INHERIT,
139
- is_page_streaming: :OPTION_INHERIT)
146
+ # is starting with this page_token.
147
+ def initialize(timeout: :OPTION_INHERIT,
148
+ retry_options: :OPTION_INHERIT,
149
+ page_token: :OPTION_INHERIT)
140
150
  @timeout = timeout
141
151
  @retry_options = retry_options
142
- @is_page_streaming = is_page_streaming
152
+ @page_token = page_token
143
153
  end
144
154
  end
145
155
 
146
156
  # Describes the structure of a page-streaming call.
147
- class PageDescriptor < Struct.new(
148
- :request_page_token_field,
149
- :response_page_token_field,
150
- :resource_field)
157
+ class PageDescriptor < Struct.new(:request_page_token_field,
158
+ :response_page_token_field,
159
+ :resource_field)
151
160
  end
152
161
 
153
162
  # Per-call configurable settings for retrying upon transient failure.
@@ -168,7 +177,8 @@ module Google
168
177
  :initial_rpc_timeout_millis,
169
178
  :rpc_timeout_multiplier,
170
179
  :max_rpc_timeout_millis,
171
- :total_timeout_millis)
180
+ :total_timeout_millis
181
+ )
172
182
  # @!attribute initial_retry_delay_millis
173
183
  # @return [Numeric] the initial delay time, in milliseconds,
174
184
  # between the completion of the first failed request and the
@@ -204,13 +214,12 @@ module Google
204
214
  # request_discriminator_fields may include '.' as a separator, which is
205
215
  # used to indicate object traversal. This allows fields in nested objects
206
216
  # to be used to determine what requests to bundle.
207
- class BundleDescriptor < Struct.new(
208
- :bundled_field,
209
- :request_discriminator_fields,
210
- :subresponse_field)
217
+ class BundleDescriptor < Struct.new(:bundled_field,
218
+ :request_discriminator_fields,
219
+ :subresponse_field)
211
220
  # @!attribute bundled_field
212
221
  # @return [String] the repeated field in the request message
213
- # that will have its elements aggregated by bundling
222
+ # that will have its elements aggregated by bundling.
214
223
  # @!attribute request_discriminator_fields
215
224
  # @return [Array<String>] a list of fields in the target
216
225
  # request message class that are used to determine which
@@ -230,12 +239,11 @@ module Google
230
239
  #
231
240
  # The xxx_threshold attributes are used to configure when the bundled
232
241
  # request should be made.
233
- class BundleOptions < Struct.new(
234
- :element_count_threshold,
235
- :element_count_limit,
236
- :request_byte_threshold,
237
- :request_byte_limit,
238
- :delay_threshold)
242
+ class BundleOptions < Struct.new(:element_count_threshold,
243
+ :element_count_limit,
244
+ :request_byte_threshold,
245
+ :request_byte_limit,
246
+ :delay_threshold)
239
247
  # @!attribute element_count_threshold
240
248
  # @return [Numeric] the bundled request will be sent once the
241
249
  # count of outstanding elements in the repeated field
@@ -265,12 +273,11 @@ module Google
265
273
  # @return [Numeric] the bundled request will be sent this
266
274
  # amount of time after the first element in the bundle was
267
275
  # added to it.
268
- def initialize(
269
- element_count_threshold: 0,
270
- element_count_limit: 0,
271
- request_byte_threshold: 0,
272
- request_byte_limit: 0,
273
- delay_threshold: 0)
276
+ def initialize(element_count_threshold: 0,
277
+ element_count_limit: 0,
278
+ request_byte_threshold: 0,
279
+ request_byte_limit: 0,
280
+ delay_threshold: 0)
274
281
  super(
275
282
  element_count_threshold,
276
283
  element_count_limit,
@@ -33,6 +33,7 @@ require 'google/gax/errors'
33
33
  require 'google/gax/grpc'
34
34
 
35
35
  # rubocop:disable Metrics/ModuleLength
36
+
36
37
  module Google
37
38
  module Gax
38
39
  MILLIS_PER_SECOND = 1000.0
@@ -44,14 +45,37 @@ module Google
44
45
  # PagedEnumerable provides the enumerations over the resource data,
45
46
  # and also provides the enumerations over the pages themselves.
46
47
  #
48
+ # Example 1: normal iteration over resources.
49
+ # paged_enumerable.each { |resource| puts resource }
50
+ #
51
+ # Example 2: per-page iteration.
52
+ # paged_enumerable.each_page { |page| puts page }
53
+ #
54
+ # Example 3: Enumerable over pages.
55
+ # pages = paged_enumerable.enum_for(:each_page).to_a
56
+ #
57
+ # Example 4: more exact operations over pages.
58
+ # while some_condition()
59
+ # page = paged_enumerable.page
60
+ # do_something(page)
61
+ # break if paged_enumerable.next_page?
62
+ # paged_enumerable.next_page
63
+ # end
64
+ #
47
65
  # @attribute [r] page
48
66
  # @return [Page] The current page object.
67
+ # @attribute [r] response
68
+ # @return [Object] The current response object.
69
+ # @attribute [r] page_token
70
+ # @return [Object] The page token to be used for the next API call.
49
71
  class PagedEnumerable
50
72
  # A class to represent a page in a PagedEnumerable. This also implements
51
73
  # Enumerable, so it can iterate over the resource elements.
52
74
  #
53
75
  # @attribute [r] response
54
- # @return [Object] The actual response object.
76
+ # @return [Object] the actual response object.
77
+ # @attribute [r] next_page_token
78
+ # @return [Object] the page token to be used for the next API call.
55
79
  class Page
56
80
  include Enumerable
57
81
  attr_reader :response
@@ -112,14 +136,17 @@ module Google
112
136
  end
113
137
 
114
138
  # Initiate the streaming with the requests and keywords.
139
+ # @param page_token [Object]
140
+ # The page token for the first page to be streamed, or nil.
115
141
  # @param request [Object]
116
142
  # The initial request object.
117
143
  # @param kwargs [Hash]
118
144
  # Other keyword arguments to be passed to a_func.
119
145
  # @return [PagedEnumerable]
120
146
  # returning self for further uses.
121
- def start(request, **kwargs)
147
+ def start(page_token, request, **kwargs)
122
148
  @request = request
149
+ @request[@request_page_token_field] = page_token if page_token
123
150
  @kwargs = kwargs
124
151
  @page = @page.dup_with(@func.call(@request, **@kwargs))
125
152
  self
@@ -143,9 +170,9 @@ module Google
143
170
 
144
171
  # Iterate over the pages.
145
172
  # @yield [Page] Gives the pages in the stream.
146
- # @raise [RuntimeError] if it's not started yet.
173
+ # @raise [GaxError] if it's not started yet.
147
174
  def each_page
148
- raise 'not started!' unless started?
175
+ raise GaxError, 'not started!' unless started?
149
176
  yield @page
150
177
  loop do
151
178
  break unless next_page?
@@ -165,6 +192,14 @@ module Google
165
192
  @request[@request_page_token_field] = @page.next_page_token
166
193
  @page = @page.dup_with(@func.call(@request, **@kwargs))
167
194
  end
195
+
196
+ def response
197
+ @page.response
198
+ end
199
+
200
+ def page_token
201
+ @page.next_page_token
202
+ end
168
203
  end
169
204
 
170
205
  # rubocop:disable Metrics/AbcSize
@@ -190,9 +225,9 @@ module Google
190
225
  # e.g, if bundling and page_streaming are both configured
191
226
  def create_api_call(func, settings)
192
227
  api_call = if settings.retry_codes?
193
- _retryable(func, settings.retry_options)
228
+ retryable(func, settings.retry_options)
194
229
  else
195
- _add_timeout_arg(func, settings.timeout)
230
+ add_timeout_arg(func, settings.timeout)
196
231
  end
197
232
 
198
233
  if settings.page_descriptor
@@ -200,18 +235,20 @@ module Google
200
235
  raise 'ApiCallable has incompatible settings: ' \
201
236
  'bundling and page streaming'
202
237
  end
203
- return _page_streamable(
238
+ return page_streamable(
204
239
  api_call,
205
240
  settings.page_descriptor.request_page_token_field,
206
241
  settings.page_descriptor.response_page_token_field,
207
- settings.page_descriptor.resource_field)
242
+ settings.page_descriptor.resource_field,
243
+ settings.page_token
244
+ )
208
245
  end
209
246
  if settings.bundler?
210
- return _bundleable(api_call, settings.bundle_descriptor,
211
- settings.bundler)
247
+ return bundleable(api_call, settings.bundle_descriptor,
248
+ settings.bundler)
212
249
  end
213
250
 
214
- _catch_errors(api_call)
251
+ catch_errors(api_call)
215
252
  end
216
253
 
217
254
  # Updates a_func to wrap exceptions with GaxError
@@ -219,16 +256,12 @@ module Google
219
256
  # @param a_func [Proc]
220
257
  # @param errors [Array<Exception>] Configures the exceptions to wrap.
221
258
  # @return [Proc] A proc that will wrap certain exceptions with GaxError
222
- def _catch_errors(a_func, errors: Grpc::API_ERRORS)
259
+ def catch_errors(a_func, errors: Grpc::API_ERRORS)
223
260
  proc do |request, **kwargs|
224
261
  begin
225
262
  a_func.call(request, **kwargs)
226
- rescue => err
227
- if errors.any? { |eclass| err.is_a? eclass }
228
- raise GaxError.new('RPC failed', cause: err)
229
- else
230
- raise err
231
- end
263
+ rescue *errors
264
+ raise GaxError, 'RPC failed'
232
265
  end
233
266
  end
234
267
  end
@@ -248,11 +281,10 @@ module Google
248
281
  # @param bundler orchestrates bundling.
249
282
  # @return [Proc] A proc takes the API call's request and returns
250
283
  # an Event object.
251
- def _bundleable(a_func, desc, bundler)
284
+ def bundleable(a_func, desc, bundler)
252
285
  proc do |request|
253
- the_id = bundling.compute_bundle_id(
254
- request,
255
- desc.request_discriminator_fields)
286
+ the_id = bundling.compute_bundle_id(request,
287
+ desc.request_discriminator_fields)
256
288
  return bundler.schedule(a_func, the_id, desc, request)
257
289
  end
258
290
  end
@@ -265,17 +297,21 @@ module Google
265
297
  # @param response_page_token_field [String] The field of the next
266
298
  # page token in the response.
267
299
  # @param resource_field [String] The field to be streamed.
300
+ # @param page_token [Object] The page_token for the first page to be
301
+ # streamed, or nil.
268
302
  # @return [Proc] A proc that returns an iterable over the specified field.
269
- def _page_streamable(
270
- a_func,
271
- request_page_token_field,
272
- response_page_token_field,
273
- resource_field)
303
+ def page_streamable(a_func,
304
+ request_page_token_field,
305
+ response_page_token_field,
306
+ resource_field,
307
+ page_token)
274
308
  enumerable = PagedEnumerable.new(a_func,
275
309
  request_page_token_field,
276
310
  response_page_token_field,
277
311
  resource_field)
278
- enumerable.method(:start)
312
+ proc do |request, **kwargs|
313
+ enumerable.start(page_token, request, **kwargs)
314
+ end
279
315
  end
280
316
 
281
317
  # rubocop:disable Metrics/MethodLength
@@ -288,7 +324,7 @@ module Google
288
324
  # upon which the proc should retry, and the parameters to the
289
325
  # exponential backoff retry algorithm.
290
326
  # @return [Proc] A proc that will retry on exception.
291
- def _retryable(a_func, retry_options)
327
+ def retryable(a_func, retry_options)
292
328
  delay_mult = retry_options.backoff_settings.retry_delay_multiplier
293
329
  max_delay = (retry_options.backoff_settings.max_retry_delay_millis /
294
330
  MILLIS_PER_SECOND)
@@ -302,32 +338,29 @@ module Google
302
338
  delay = retry_options.backoff_settings.initial_retry_delay_millis
303
339
  timeout = (retry_options.backoff_settings.initial_rpc_timeout_millis /
304
340
  MILLIS_PER_SECOND)
305
- exc = nil
306
341
  result = nil
307
342
  now = Time.now
308
343
  deadline = now + total_timeout
309
344
 
310
- while now < deadline
345
+ loop do
311
346
  begin
312
- exc = nil
313
- result = _add_timeout_arg(a_func, timeout).call(request, **kwargs)
347
+ result = add_timeout_arg(a_func, timeout).call(request, **kwargs)
314
348
  break
315
349
  rescue => exception
316
350
  unless exception.respond_to?(:code) &&
317
351
  retry_options.retry_codes.include?(exception.code)
318
- raise RetryError.new('Exception occurred in retry method that ' \
319
- 'was not classified as transient',
320
- cause: exception)
352
+ raise RetryError, 'Exception occurred in retry method that ' \
353
+ 'was not classified as transient'
321
354
  end
322
- exc = RetryError.new('Retry total timeout exceeded with exception',
323
- cause: exception)
324
355
  sleep(rand(delay) / MILLIS_PER_SECOND)
325
356
  now = Time.now
326
357
  delay = [delay * delay_mult, max_delay].min
327
358
  timeout = [timeout * timeout_mult, max_timeout, deadline - now].min
359
+ if now >= deadline
360
+ raise RetryError, 'Retry total timeout exceeded with exception'
361
+ end
328
362
  end
329
363
  end
330
- raise exc unless exc.nil?
331
364
  result
332
365
  end
333
366
  end
@@ -341,16 +374,16 @@ module Google
341
374
  # @param timeout [Numeric] to be added to the original proc as it
342
375
  # final positional arg.
343
376
  # @return [Proc] the original proc updated to the timeout arg
344
- def _add_timeout_arg(a_func, timeout)
377
+ def add_timeout_arg(a_func, timeout)
345
378
  proc do |request, **kwargs|
346
379
  kwargs[:timeout] = timeout
347
380
  a_func.call(request, **kwargs)
348
381
  end
349
382
  end
350
383
 
351
- module_function :create_api_call, :_catch_errors, :_bundleable,
352
- :_page_streamable, :_retryable, :_add_timeout_arg
353
- private_class_method :_catch_errors, :_bundleable, :_page_streamable,
354
- :_retryable, :_add_timeout_arg
384
+ module_function :create_api_call, :catch_errors, :bundleable,
385
+ :page_streamable, :retryable, :add_timeout_arg
386
+ private_class_method :catch_errors, :bundleable, :page_streamable,
387
+ :retryable, :add_timeout_arg
355
388
  end
356
389
  end
@@ -27,20 +27,26 @@
27
27
  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
28
  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
29
 
30
+ require 'English'
31
+
30
32
  module Google
31
33
  module Gax
32
34
  # Common base class for exceptions raised by GAX.
33
35
  class GaxError < StandardError
34
- attr_reader :cause
35
-
36
36
  # @param msg [String] describes the error that occurred.
37
- # @param cause [Error] the exception raised by a lower layer of
38
- # the RPC stack (for example, gRPC) that caused this
39
- # exception, or None if this exception originated in GAX.
40
- def initialize(msg, cause:nil)
41
- msg = "GaxError #{msg}, caused by #{cause}" if cause
37
+ def initialize(msg)
38
+ msg = "GaxError #{msg}"
39
+ msg += ", caused by #{$ERROR_INFO}" if $ERROR_INFO
42
40
  super(msg)
43
- @cause = cause
41
+ @cause = $ERROR_INFO
42
+ end
43
+
44
+ # cause is a new method introduced in 2.1.0, bring this
45
+ # method if it does not exist.
46
+ unless respond_to?(:cause)
47
+ define_method(:cause) do
48
+ @cause
49
+ end
44
50
  end
45
51
  end
46
52
 
@@ -34,9 +34,11 @@ module Google
34
34
  module Gax
35
35
  # Grpc adapts the gRPC surface
36
36
  module Grpc
37
- STATUS_CODE_NAMES = GRPC::Core::StatusCodes.constants.map do |sym|
38
- [sym.to_s, GRPC::Core::StatusCodes.const_get(sym)]
39
- end.to_h.freeze
37
+ STATUS_CODE_NAMES = Hash[
38
+ GRPC::Core::StatusCodes.constants.map do |sym|
39
+ [sym.to_s, GRPC::Core::StatusCodes.const_get(sym)]
40
+ end
41
+ ].freeze
40
42
 
41
43
  API_ERRORS = [GRPC::BadStatus, GRPC::Cancelled].freeze
42
44
 
@@ -48,20 +50,21 @@ module Google
48
50
  #
49
51
  # @param port [Fixnum] The port on which to connect to the remote host.
50
52
  #
51
- # @param chan_creds [Object] A ClientCredentials object for use with an
52
- # SSL-enabled Channel. If none, credentials are pulled from a default
53
- # location.
53
+ # @param chan_creds [Grpc::Core::ChannelCredentials]
54
+ # A ChannelCredentials object for use with an SSL-enabled Channel.
55
+ # If nil, credentials are pulled from a default location.
54
56
  #
55
- # @param channel [Object] A Channel object through which to make calls. If
56
- # none, a secure channel is constructed.
57
+ # @param channel [Object]
58
+ # A Channel object through which to make calls. If nil, a secure
59
+ # channel is constructed.
57
60
  #
58
61
  # @param updater_proc [Proc]
59
- # A function that transforms the metadata for requests, e.g., to give
60
- # OAuth credentials.
62
+ # A function that transforms the metadata for requests, e.g., to give
63
+ # OAuth credentials.
61
64
  #
62
65
  # @param scopes [Array<String>]
63
- # The OAuth scopes for this service. This parameter is ignored if
64
- # a custom metadata_transformer is supplied.
66
+ # The OAuth scopes for this service. This parameter is ignored if
67
+ # a custom metadata_transformer is supplied.
65
68
  #
66
69
  # @yield [address, creds]
67
70
  # the generated gRPC method to create a stub.
@@ -216,7 +216,8 @@ module Google
216
216
  i += size
217
217
  elsif segment.literal != that[i]
218
218
  throw ArgumentError.new(
219
- "mismatched literal: '#{segment.literal}' != '#{that[i]}'")
219
+ "mismatched literal: '#{segment.literal}' != '#{that[i]}'"
220
+ )
220
221
  else
221
222
  i += 1
222
223
  end
@@ -226,7 +227,8 @@ module Google
226
227
  end
227
228
  if i != that.size || i != segment_count
228
229
  throw ArgumentError.new(
229
- "match error: could not instantiate a path template from #{path}")
230
+ "match error: could not instantiate a path template from #{path}"
231
+ )
230
232
  end
231
233
  bindings
232
234
  end
@@ -31,32 +31,23 @@ module Google
31
31
  module Gax
32
32
  # Helper for #construct_settings
33
33
  #
34
- # @param method_config A dictionary representing a single
35
- # ``methods`` entry of the standard API client config file. (See
36
- # #construct_settings for information on this yaml.)
37
- # @param method_retry_override [BundleOptions, :OPTION_INHERIT, nil]
38
- # If set to :OPTION_INHERIT, the retry settings are derived from
39
- # method config. Otherwise, this parameter overrides
40
- # +method_config+.
41
-
34
+ # @param bundle_config A Hash specifying a bundle parameters, the value for
35
+ # 'bundling' field in a method config (See ``construct_settings()`` for
36
+ # information on this config.)
42
37
  # @param bundle_descriptor [BundleDescriptor] A BundleDescriptor
43
38
  # object describing the structure of bundling for this
44
39
  # method. If not set, this method will not bundle.
45
40
  # @return An Executor that configures bundling, or nil if this
46
41
  # method should not bundle.
47
- def _construct_bundling(method_config, method_bundling_override,
48
- bundle_descriptor)
49
- if method_config.key?('bundling') && bundle_descriptor
50
- if method_bundling_override == :OPTION_INHERIT
51
- options = BundleOptions.new
52
- method_config['bundling'].each_pair do |key, value|
53
- options[key.intern] = value
54
- end
55
- # TODO: comment-out when bundling is supported.
56
- # Executor.new(options)
57
- elsif method_bundling_override
58
- # Executor.new(method_bundling_override)
42
+ def construct_bundling(bundle_config, bundle_descriptor)
43
+ if bundle_config && bundle_descriptor
44
+ options = BundleOptions.new
45
+ bundle_config.each_pair do |key, value|
46
+ options[key.intern] = value
59
47
  end
48
+ # TODO: comment-out when bundling is supported.
49
+ # Executor.new(options)
50
+ nil
60
51
  end
61
52
  end
62
53
 
@@ -65,11 +56,7 @@ module Google
65
56
  # @param method_config [Hash] A dictionary representing a single
66
57
  # +methods+ entry of the standard API client config file. (See
67
58
  # #construct_settings for information on this yaml.)
68
- # @param method_retry_override [RetryOptions, :OPTION_INHERIT, nil]
69
- # If set to :OPTION_INHERIT, the retry settings are derived from
70
- # method config. Otherwise, this parameter overrides
71
- # +method_config+.
72
- # @param retry_codes_def [Hash] A dictionary parsed from the
59
+ # @param retry_codes [Hash] A dictionary parsed from the
73
60
  # +retry_codes_def+ entry of the standard API client config
74
61
  # file. (See #construct_settings for information on this yaml.)
75
62
  # @param retry_params [Hash] A dictionary parsed from the
@@ -79,28 +66,55 @@ module Google
79
66
  # used in the standard API client config file to API response
80
67
  # status codes.
81
68
  # @return [RetryOptions, nil]
82
- def _construct_retry(method_config, method_retry_override, retry_codes,
83
- retry_params, retry_names)
84
- unless method_retry_override == :OPTION_INHERIT
85
- return method_retry_override
86
- end
87
-
88
- retry_codes ||= {}
89
- retry_codes_name = method_config['retry_codes_name']
90
- codes = retry_codes.fetch(retry_codes_name, []).map do |name|
91
- retry_names[name]
69
+ def construct_retry(method_config, retry_codes, retry_params, retry_names)
70
+ return nil unless method_config
71
+ codes = nil
72
+ if retry_codes && method_config.key?('retry_codes_name')
73
+ retry_codes_name = method_config['retry_codes_name']
74
+ codes = retry_codes.fetch(retry_codes_name, []).map do |name|
75
+ retry_names[name]
76
+ end
92
77
  end
93
78
 
79
+ backoff_settings = nil
94
80
  if retry_params && method_config.key?('retry_params_name')
95
81
  params = retry_params[method_config['retry_params_name']]
96
82
  backoff_settings = BackoffSettings.new(
97
- *params.values_at(*BackoffSettings.members.map(&:to_s)))
83
+ *params.values_at(*BackoffSettings.members.map(&:to_s))
84
+ )
98
85
  end
99
86
 
100
87
  RetryOptions.new(codes, backoff_settings)
101
88
  end
102
89
 
103
- def _upper_camel_to_lower_underscore(string)
90
+ # Helper for #construct_settings.
91
+ #
92
+ # Takes two retry options, and merges them into a single RetryOption
93
+ # instance.
94
+ #
95
+ # @param retry_options [RetryOptions] The base RetryOptions.
96
+ # @param overrides [RetryOptions] The RetryOptions used for overriding
97
+ # +retry+. Use the values if it is not nil. If entire
98
+ # +overrides+ is nli, ignore the base retry and return nil.
99
+ # @return [RetryOptions, nil]
100
+ def merge_retry_options(retry_options, overrides)
101
+ return nil if overrides.nil?
102
+
103
+ if overrides.retry_codes.nil? && overrides.backoff_settings.nil?
104
+ return retry_options
105
+ end
106
+
107
+ codes = retry_options.retry_codes
108
+ codes = overrides.retry_codes unless overrides.retry_codes.nil?
109
+ backoff_settings = retry_options.backoff_settings
110
+ unless overrides.backoff_settings.nil?
111
+ backoff_settings = overrides.backoff_settings
112
+ end
113
+
114
+ RetryOptions.new(codes, backoff_settings)
115
+ end
116
+
117
+ def upper_camel_to_lower_underscore(string)
104
118
  string.scan(/[[:upper:]][^[:upper:]]*/).map(&:downcase).join('_')
105
119
  end
106
120
 
@@ -154,12 +168,10 @@ module Google
154
168
  # service, used as a key into the client config file (in the
155
169
  # example above, this value should be
156
170
  # 'google.fake.v1.ServiceName').
157
- # @param client_config [Hash] A dictionary parsed from the
158
- # standard API client config file.
159
- # @param bundling_override [Hash] A dictionary of method names to
160
- # BundleOptions override those specified in +client_config+.
161
- # @param retry_override [Hash] A dictionary of method names to
162
- # RetryOptions that override those specified in +client_config+.
171
+ # @param client_config [Hash] A hash parsed from the standard
172
+ # API client config file.
173
+ # @param config_overrides [Hash] A hash in the same structure of
174
+ # client_config to override the settings.
163
175
  # @param retry_names [Hash] A dictionary mapping the strings
164
176
  # referring to response status codes to the Python objects
165
177
  # representing those codes.
@@ -173,41 +185,55 @@ module Google
173
185
  # methods that are page streaming-enabled.
174
186
  # @return [CallSettings, nil] A CallSettings, or nil if the
175
187
  # service is not found in the config.
176
- def construct_settings(
177
- service_name, client_config, bundling_override, retry_override,
178
- retry_names, timeout, bundle_descriptors: {}, page_descriptors: {})
188
+ def construct_settings(service_name, client_config, config_overrides,
189
+ retry_names, timeout, bundle_descriptors: {},
190
+ page_descriptors: {})
179
191
  defaults = {}
180
192
 
181
193
  service_config = client_config.fetch('interfaces', {})[service_name]
182
194
  return nil unless service_config
183
195
 
196
+ overrides = config_overrides.fetch('interfaces', {})[service_name] || {}
197
+
184
198
  service_config['methods'].each_pair do |method_name, method_config|
185
- snake_name = _upper_camel_to_lower_underscore(method_name)
199
+ snake_name = upper_camel_to_lower_underscore(method_name)
186
200
 
201
+ overriding_method =
202
+ overrides.fetch('methods', {}).fetch(method_name, {})
203
+
204
+ bundling_config = method_config.fetch('bundling', nil)
205
+ if overriding_method && overriding_method.key?('bundling')
206
+ bundling_config = overriding_method['bundling']
207
+ end
187
208
  bundle_descriptor = bundle_descriptors[snake_name]
188
209
 
189
210
  defaults[snake_name] = CallSettings.new(
190
211
  timeout: timeout,
191
- retry_options: _construct_retry(
192
- method_config,
193
- retry_override.fetch(snake_name, :OPTION_INHERIT),
194
- service_config['retry_codes'],
195
- service_config['retry_params'],
196
- retry_names),
212
+ retry_options: merge_retry_options(
213
+ construct_retry(method_config,
214
+ service_config['retry_codes'],
215
+ service_config['retry_params'],
216
+ retry_names),
217
+ construct_retry(overriding_method,
218
+ overrides['retry_codes'],
219
+ overrides['retry_params'],
220
+ retry_names)
221
+ ),
197
222
  page_descriptor: page_descriptors[snake_name],
198
- bundler: _construct_bundling(
199
- method_config,
200
- bundling_override.fetch(snake_name, :OPTION_INHERIT),
201
- bundle_descriptor),
202
- bundle_descriptor: bundle_descriptor)
223
+ bundler: construct_bundling(bundling_config,
224
+ bundle_descriptor),
225
+ bundle_descriptor: bundle_descriptor
226
+ )
203
227
  end
204
228
 
205
229
  defaults
206
230
  end
207
231
 
208
- module_function :construct_settings, :_construct_bundling,
209
- :_construct_retry, :_upper_camel_to_lower_underscore
210
- private_class_method :_construct_bundling, :_construct_retry,
211
- :_upper_camel_to_lower_underscore
232
+ module_function :construct_settings, :construct_bundling,
233
+ :construct_retry, :upper_camel_to_lower_underscore,
234
+ :merge_retry_options
235
+ private_class_method :construct_bundling, :construct_retry,
236
+ :upper_camel_to_lower_underscore,
237
+ :merge_retry_options
212
238
  end
213
239
  end
@@ -29,6 +29,6 @@
29
29
 
30
30
  module Google
31
31
  module Gax
32
- VERSION = '0.1.3'.freeze
32
+ VERSION = '0.3.0'.freeze
33
33
  end
34
34
  end
@@ -63,8 +63,8 @@ describe Google::Gax do
63
63
  page_size = 3
64
64
  pages_to_stream = 5
65
65
 
66
- page_descriptor = Google::Gax::PageDescriptor.new(
67
- 'page_token', 'next_page_token', 'nums')
66
+ page_descriptor = Google::Gax::PageDescriptor.new('page_token',
67
+ 'next_page_token', 'nums')
68
68
  settings = CallSettings.new(page_descriptor: page_descriptor)
69
69
  timeout_arg = nil
70
70
  func = proc do |request, timeout: nil|
@@ -82,8 +82,9 @@ describe Google::Gax do
82
82
 
83
83
  it 'iterates over elements' do
84
84
  my_callable = Google::Gax.create_api_call(func, settings)
85
- expect(my_callable.call('page_token' => 0).to_a).to eq(
86
- (0...(page_size * pages_to_stream)).to_a)
85
+ expect(my_callable.call('page_token' => 0).to_a).to match_array(
86
+ (0...(page_size * pages_to_stream))
87
+ )
87
88
  expect(timeout_arg).to_not be_nil
88
89
  end
89
90
 
@@ -99,14 +100,59 @@ describe Google::Gax do
99
100
  stream = my_callable.call('page_token' => 0)
100
101
  expect(stream.enum_for(:each_page).to_a.size).to eq(pages_to_stream + 1)
101
102
  end
103
+
104
+ it 'starts from the specified page_token' do
105
+ my_settings = settings.merge(Google::Gax::CallOptions.new(page_token: 3))
106
+ my_callable = Google::Gax.create_api_call(func, my_settings)
107
+ expect(my_callable.call({}).to_a).to match_array(
108
+ 3...(page_size * pages_to_stream)
109
+ )
110
+ end
111
+ end
112
+
113
+ describe 'failures without retry' do
114
+ it 'simply fails' do
115
+ settings = CallSettings.new
116
+ timeout_arg = nil
117
+ call_count = 0
118
+ func = proc do |timeout: nil|
119
+ timeout_arg = timeout
120
+ call_count += 1
121
+ raise GRPC::Cancelled, ''
122
+ end
123
+ my_callable = Google::Gax.create_api_call(func, settings)
124
+ begin
125
+ my_callable.call
126
+ expect(true).to be false # should not reach to this line.
127
+ rescue Google::Gax::GaxError => exc
128
+ expect(exc.cause).to be_a(GRPC::Cancelled)
129
+ end
130
+ expect(timeout_arg).to_not be_nil
131
+ expect(call_count).to eq(1)
132
+ end
133
+
134
+ it 'does not wrap unknown errors' do
135
+ settings = CallSettings.new
136
+ timeout_arg = nil
137
+ call_count = 0
138
+ func = proc do |timeout: nil|
139
+ timeout_arg = timeout
140
+ call_count += 1
141
+ raise CustomException.new('', FAKE_STATUS_CODE_1)
142
+ end
143
+ my_callable = Google::Gax.create_api_call(func, settings)
144
+ expect { my_callable.call }.to raise_error(CustomException)
145
+ expect(timeout_arg).to_not be_nil
146
+ expect(call_count).to eq(1)
147
+ end
102
148
  end
103
149
 
104
150
  describe 'retryable' do
105
151
  RetryOptions = Google::Gax::RetryOptions
106
152
  BackoffSettings = Google::Gax::BackoffSettings
107
153
 
108
- retry_options = RetryOptions.new(
109
- [FAKE_STATUS_CODE_1], BackoffSettings.new(0, 0, 0, 0, 0, 0, 1))
154
+ retry_options = RetryOptions.new([FAKE_STATUS_CODE_1],
155
+ BackoffSettings.new(0, 0, 0, 0, 0, 0, 1))
110
156
  settings = CallSettings.new(timeout: 0, retry_options: retry_options)
111
157
 
112
158
  it 'retries the API call' do
@@ -138,7 +184,8 @@ describe Google::Gax do
138
184
  raise CustomException.new('', FAKE_STATUS_CODE_1)
139
185
  end
140
186
  my_callable = Google::Gax.create_api_call(
141
- func, CallSettings.new(timeout: 0, retry_options: retry_options))
187
+ func, CallSettings.new(timeout: 0, retry_options: retry_options)
188
+ )
142
189
  expect { my_callable.call }.to raise_error(Google::Gax::RetryError)
143
190
  expect(call_count).to eq(1)
144
191
  end
@@ -160,7 +207,8 @@ describe Google::Gax do
160
207
 
161
208
  time_now = Time.now
162
209
  allow(Time).to receive(:now).exactly(4).times.and_return(
163
- *([time_now] * to_attempt + [time_now + 2]))
210
+ *([time_now] * to_attempt + [time_now + 2])
211
+ )
164
212
 
165
213
  func = proc do
166
214
  call_count += 1
@@ -170,7 +218,7 @@ describe Google::Gax do
170
218
  my_callable = Google::Gax.create_api_call(func, settings)
171
219
  begin
172
220
  my_callable.call
173
- except(true).to be false # should not reach to this line.
221
+ expect(true).to be false # should not reach to this line.
174
222
  rescue Google::Gax::RetryError => exc
175
223
  expect(exc.cause).to be_a(CustomException)
176
224
  end
@@ -210,7 +258,8 @@ describe Google::Gax do
210
258
  backoff = BackoffSettings.new(3, 2, 24, 5, 2, 80, 2500)
211
259
  retry_options = RetryOptions.new([FAKE_STATUS_CODE_1], backoff)
212
260
  my_callable = Google::Gax.create_api_call(
213
- func, CallSettings.new(timeout: 0, retry_options: retry_options))
261
+ func, CallSettings.new(timeout: 0, retry_options: retry_options)
262
+ )
214
263
 
215
264
  begin
216
265
  my_callable.call(0)
@@ -69,7 +69,8 @@ describe Google::Gax::PathTemplate do
69
69
  template = PathTemplate.new('hello/world')
70
70
  expect { template.match('hello') }.to raise_error(ArgumentError)
71
71
  expect { template.match('hello/world/fail') }.to raise_error(
72
- ArgumentError)
72
+ ArgumentError
73
+ )
73
74
  end
74
75
 
75
76
  it 'should fail on mismatched literal' do
@@ -71,7 +71,8 @@ A_CONFIG = {
71
71
 
72
72
  PAGE_DESCRIPTORS = {
73
73
  'page_streaming_method' => Google::Gax::PageDescriptor.new(
74
- 'page_token', 'next_page_token', 'page_streams')
74
+ 'page_token', 'next_page_token', 'page_streams'
75
+ )
75
76
  }.freeze
76
77
 
77
78
  BUNDLE_DESCRIPTORS = {
@@ -87,9 +88,10 @@ RETRY_DICT = {
87
88
  describe Google::Gax do
88
89
  it 'creates settings' do
89
90
  defaults = Google::Gax.construct_settings(
90
- SERVICE_NAME, A_CONFIG, {}, {}, RETRY_DICT, 30,
91
+ SERVICE_NAME, A_CONFIG, {}, RETRY_DICT, 30,
91
92
  bundle_descriptors: BUNDLE_DESCRIPTORS,
92
- page_descriptors: PAGE_DESCRIPTORS)
93
+ page_descriptors: PAGE_DESCRIPTORS
94
+ )
93
95
  settings = defaults['bundling_method']
94
96
  expect(settings.timeout).to be(30)
95
97
  # TODO: uncomment this when bundling is added.
@@ -99,7 +101,8 @@ describe Google::Gax do
99
101
  expect(settings.retry_options).to be_a(Google::Gax::RetryOptions)
100
102
  expect(settings.retry_options.retry_codes).to be_a(Array)
101
103
  expect(settings.retry_options.backoff_settings).to be_a(
102
- Google::Gax::BackoffSettings)
104
+ Google::Gax::BackoffSettings
105
+ )
103
106
 
104
107
  settings = defaults['page_streaming_method']
105
108
  expect(settings.timeout).to be(30)
@@ -109,17 +112,28 @@ describe Google::Gax do
109
112
  expect(settings.retry_options).to be_a(Google::Gax::RetryOptions)
110
113
  expect(settings.retry_options.retry_codes).to be_a(Array)
111
114
  expect(settings.retry_options.backoff_settings).to be_a(
112
- Google::Gax::BackoffSettings)
115
+ Google::Gax::BackoffSettings
116
+ )
113
117
  end
114
118
 
115
119
  it 'overrides settings' do
116
- bundling_override = { 'bundling_method' => nil }
117
- retry_override = { 'page_streaming_method' => nil }
120
+ overrides = {
121
+ 'interfaces' => {
122
+ SERVICE_NAME => {
123
+ 'methods' => {
124
+ 'PageStreamingMethod' => nil,
125
+ 'BundlingMethod' => {
126
+ 'bundling' => nil
127
+ }
128
+ }
129
+ }
130
+ }
131
+ }
118
132
  defaults = Google::Gax.construct_settings(
119
- SERVICE_NAME, A_CONFIG, bundling_override, retry_override,
120
- RETRY_DICT, 30,
133
+ SERVICE_NAME, A_CONFIG, overrides, RETRY_DICT, 30,
121
134
  bundle_descriptors: BUNDLE_DESCRIPTORS,
122
- page_descriptors: PAGE_DESCRIPTORS)
135
+ page_descriptors: PAGE_DESCRIPTORS
136
+ )
123
137
 
124
138
  settings = defaults['bundling_method']
125
139
  expect(settings.timeout).to be(30)
@@ -131,4 +145,60 @@ describe Google::Gax do
131
145
  expect(settings.page_descriptor).to be_a(Google::Gax::PageDescriptor)
132
146
  expect(settings.retry_options).to be_nil
133
147
  end
148
+
149
+ it 'overrides settings more precisely' do
150
+ override = {
151
+ 'interfaces' => {
152
+ SERVICE_NAME => {
153
+ 'retry_codes' => {
154
+ 'bar_retry' => [],
155
+ 'baz_retry' => ['code_a']
156
+ },
157
+ 'retry_params' => {
158
+ 'default' => {
159
+ 'initial_retry_delay_millis' => 1000,
160
+ 'retry_delay_multiplier' => 1.2,
161
+ 'max_retry_delay_millis' => 10_000,
162
+ 'initial_rpc_timeout_millis' => 3000,
163
+ 'rpc_timeout_multiplier' => 1.3,
164
+ 'max_rpc_timeout_millis' => 30_000,
165
+ 'total_timeout_millis' => 300_000
166
+ }
167
+ },
168
+ 'methods' => {
169
+ 'BundlingMethod' => {
170
+ 'retry_params_name' => 'default',
171
+ 'retry_codes_name' => 'baz_retry'
172
+ }
173
+ }
174
+ }
175
+ }
176
+ }
177
+ defaults = Google::Gax.construct_settings(
178
+ SERVICE_NAME, A_CONFIG, override, RETRY_DICT, 30,
179
+ bundle_descriptors: BUNDLE_DESCRIPTORS,
180
+ page_descriptors: PAGE_DESCRIPTORS
181
+ )
182
+
183
+ settings = defaults['bundling_method']
184
+ backoff = settings.retry_options.backoff_settings
185
+ expect(backoff.initial_retry_delay_millis).to be(1000)
186
+ expect(settings.retry_options.retry_codes).to match_array(
187
+ [RETRY_DICT['code_a']]
188
+ )
189
+ expect(settings.bundler).to be(nil)
190
+ expect(settings.bundle_descriptor).to be_a(Google::Gax::BundleDescriptor)
191
+
192
+ # page_streaming_method is unaffected because it's not specified in
193
+ # overrides. 'bar_retry' or 'default' definitions in overrides should
194
+ # not affect the methods which are not in the overrides.
195
+ settings = defaults['page_streaming_method']
196
+ backoff = settings.retry_options.backoff_settings
197
+ expect(backoff.initial_retry_delay_millis).to be(100)
198
+ expect(backoff.retry_delay_multiplier).to be(1.2)
199
+ expect(backoff.max_retry_delay_millis).to be(1000)
200
+ expect(settings.retry_options.retry_codes).to match_array(
201
+ [RETRY_DICT['code_c']]
202
+ )
203
+ end
134
204
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-gax
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Google API Authors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-04 00:00:00.000000000 Z
11
+ date: 2016-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: googleauth
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: 0.2.3
55
- - !ruby/object:Gem::Dependency
56
- name: bundler
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '1.9'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '1.9'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: codecov
71
57
  requirement: !ruby/object:Gem::Requirement
@@ -167,7 +153,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
167
153
  requirements:
168
154
  - - ">="
169
155
  - !ruby/object:Gem::Version
170
- version: '0'
156
+ version: 2.0.0
171
157
  required_rubygems_version: !ruby/object:Gem::Requirement
172
158
  requirements:
173
159
  - - ">="