google-gax 0.1.3 → 0.3.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.
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
  - - ">="