gapic-common 0.22.0 → 0.25.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 +4 -4
- data/CHANGELOG.md +21 -0
- data/README.md +5 -5
- data/lib/gapic/call_options/error_codes.rb +2 -60
- data/lib/gapic/call_options/retry_policy.rb +10 -109
- data/lib/gapic/call_options.rb +1 -1
- data/lib/gapic/common/error_codes.rb +74 -0
- data/lib/gapic/common/polling_harness.rb +82 -0
- data/lib/gapic/common/retry_policy.rb +255 -0
- data/lib/gapic/common/version.rb +1 -1
- data/lib/gapic/common.rb +1 -0
- data/lib/gapic/grpc/service_stub/channel.rb +4 -2
- data/lib/gapic/grpc/service_stub/channel_pool.rb +9 -2
- data/lib/gapic/grpc/service_stub/rpc_call.rb +120 -12
- data/lib/gapic/grpc/service_stub.rb +15 -3
- data/lib/gapic/headers.rb +5 -1
- data/lib/gapic/logging_concerns.rb +210 -0
- data/lib/gapic/operation/retry_policy.rb +25 -65
- data/lib/gapic/rest/client_stub.rb +91 -18
- data/lib/gapic/universe_domain_concerns.rb +2 -2
- metadata +40 -12
data/lib/gapic/common.rb
CHANGED
@@ -32,12 +32,13 @@ module Gapic
|
|
32
32
|
# Creates a new Channel instance
|
33
33
|
#
|
34
34
|
def initialize grpc_stub_class, endpoint:, credentials:, channel_args: nil, interceptors: nil,
|
35
|
-
on_channel_create: nil
|
35
|
+
on_channel_create: nil, stub_logger: nil
|
36
36
|
@grpc_stub_class = grpc_stub_class
|
37
37
|
@endpoint = endpoint
|
38
38
|
@credentials = credentials
|
39
39
|
@channel_args = Hash channel_args
|
40
40
|
@interceptors = Array interceptors
|
41
|
+
@stub_logger = stub_logger
|
41
42
|
@concurrent_streams = 0
|
42
43
|
@mutex = Mutex.new
|
43
44
|
setup_grpc_stub
|
@@ -88,7 +89,8 @@ module Gapic
|
|
88
89
|
def call_rpc method_name, request, options: nil, &block
|
89
90
|
@mutex.synchronize { @concurrent_streams += 1 }
|
90
91
|
begin
|
91
|
-
|
92
|
+
meth = @grpc_stub.method method_name
|
93
|
+
rpc_call = RpcCall.new meth, stub_logger: @stub_logger, method_name: method_name
|
92
94
|
response = rpc_call.call request, options: options, &block
|
93
95
|
response
|
94
96
|
ensure
|
@@ -30,7 +30,12 @@ module Gapic
|
|
30
30
|
##
|
31
31
|
# Initialize an instance of ServiceStub::ChannelPool
|
32
32
|
#
|
33
|
-
def initialize grpc_stub_class,
|
33
|
+
def initialize grpc_stub_class,
|
34
|
+
endpoint:, credentials:,
|
35
|
+
channel_args: nil,
|
36
|
+
interceptors: nil,
|
37
|
+
config: nil,
|
38
|
+
stub_logger: nil
|
34
39
|
if credentials.is_a? ::GRPC::Core::Channel
|
35
40
|
raise ArgumentError, "Can't create a channel pool with GRPC::Core::Channel as credentials"
|
36
41
|
end
|
@@ -41,6 +46,7 @@ module Gapic
|
|
41
46
|
@channel_args = channel_args
|
42
47
|
@interceptors = interceptors
|
43
48
|
@config = config || Configuration.new
|
49
|
+
@stub_logger = stub_logger
|
44
50
|
|
45
51
|
@channels = (1..@config.channel_count).map { create_channel }
|
46
52
|
end
|
@@ -49,7 +55,8 @@ module Gapic
|
|
49
55
|
# Creates a new channel.
|
50
56
|
def create_channel
|
51
57
|
Channel.new @grpc_stub_class, endpoint: @endpoint, credentials: @credentials, channel_args: @channel_args,
|
52
|
-
interceptors: @interceptors, on_channel_create: @config.on_channel_create
|
58
|
+
interceptors: @interceptors, on_channel_create: @config.on_channel_create,
|
59
|
+
stub_logger: @stub_logger
|
53
60
|
end
|
54
61
|
|
55
62
|
##
|
@@ -13,6 +13,7 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
15
|
require "gapic/call_options"
|
16
|
+
require "gapic/logging_concerns"
|
16
17
|
require "grpc/errors"
|
17
18
|
|
18
19
|
module Gapic
|
@@ -32,8 +33,11 @@ module Gapic
|
|
32
33
|
#
|
33
34
|
# @param stub_method [Proc] Used to make a bare rpc call.
|
34
35
|
#
|
35
|
-
def initialize stub_method
|
36
|
+
def initialize stub_method, stub_logger: nil, method_name: nil
|
36
37
|
@stub_method = stub_method
|
38
|
+
@stub_logger = stub_logger
|
39
|
+
@method_name = method_name
|
40
|
+
@request_id = LoggingConcerns.random_uuid4
|
37
41
|
end
|
38
42
|
|
39
43
|
##
|
@@ -44,7 +48,8 @@ module Gapic
|
|
44
48
|
# customize the options object, using keys that match the arguments for {Gapic::CallOptions.new}. This object
|
45
49
|
# should only be used once.
|
46
50
|
#
|
47
|
-
# @yield [response, operation] Access the response along with the RPC operation.
|
51
|
+
# @yield [response, operation] Access the response along with the RPC operation. Additionally, throwing
|
52
|
+
# `:response, obj` within the block will change the return value to `obj`.
|
48
53
|
# @yieldparam response [Object] The response object.
|
49
54
|
# @yieldparam operation [::GRPC::ActiveCall::Operation] The RPC operation for the response.
|
50
55
|
#
|
@@ -91,7 +96,7 @@ module Gapic
|
|
91
96
|
# )
|
92
97
|
# response = echo_call.call request, options: options
|
93
98
|
#
|
94
|
-
# @example Accessing the
|
99
|
+
# @example Accessing the RPC operation using a block:
|
95
100
|
# require "google/showcase/v1beta1/echo_pb"
|
96
101
|
# require "google/showcase/v1beta1/echo_services_pb"
|
97
102
|
# require "gapic"
|
@@ -107,8 +112,8 @@ module Gapic
|
|
107
112
|
# echo_call = Gapic::ServiceStub::RpcCall.new echo_stub.method :echo
|
108
113
|
#
|
109
114
|
# request = Google::Showcase::V1beta1::EchoRequest.new
|
110
|
-
# echo_call.call request do |
|
111
|
-
# operation.trailing_metadata
|
115
|
+
# metadata = echo_call.call request do |_response, operation|
|
116
|
+
# throw :response, operation.trailing_metadata
|
112
117
|
# end
|
113
118
|
#
|
114
119
|
def call request, options: nil
|
@@ -117,21 +122,27 @@ module Gapic
|
|
117
122
|
deadline = calculate_deadline options
|
118
123
|
metadata = options.metadata
|
119
124
|
|
125
|
+
try_number = 1
|
120
126
|
retried_exception = nil
|
121
127
|
begin
|
128
|
+
request = log_request request, metadata, try_number
|
122
129
|
operation = stub_method.call request, deadline: deadline, metadata: metadata, return_op: true
|
123
130
|
response = operation.execute
|
124
|
-
|
125
|
-
|
131
|
+
catch :response do
|
132
|
+
response = log_response response, try_number
|
133
|
+
yield response, operation if block_given?
|
134
|
+
response
|
135
|
+
end
|
126
136
|
rescue ::GRPC::DeadlineExceeded => e
|
137
|
+
log_response e, try_number
|
127
138
|
raise Gapic::GRPC::DeadlineExceededError.new e.message, root_cause: retried_exception
|
128
139
|
rescue StandardError => e
|
129
|
-
|
130
|
-
|
131
|
-
end
|
140
|
+
e = normalize_exception e
|
141
|
+
log_response e, try_number
|
132
142
|
|
133
143
|
if check_retry?(deadline) && options.retry_policy.call(e)
|
134
144
|
retried_exception = e
|
145
|
+
try_number += 1
|
135
146
|
retry
|
136
147
|
end
|
137
148
|
|
@@ -145,13 +156,110 @@ module Gapic
|
|
145
156
|
return if options.timeout.nil?
|
146
157
|
return if options.timeout.negative?
|
147
158
|
|
148
|
-
|
159
|
+
current_time + options.timeout
|
149
160
|
end
|
150
161
|
|
151
162
|
def check_retry? deadline
|
152
163
|
return true if deadline.nil?
|
153
164
|
|
154
|
-
deadline >
|
165
|
+
deadline > current_time
|
166
|
+
end
|
167
|
+
|
168
|
+
def current_time
|
169
|
+
# An alternative way of saying Time.now without actually calling
|
170
|
+
# Time.now. This allows clients that replace Time.now (e.g. via the
|
171
|
+
# timecop gem) to do so without interfering with the deadline.
|
172
|
+
nanos = Process.clock_gettime Process::CLOCK_REALTIME, :nanosecond
|
173
|
+
secs_part = nanos / 1_000_000_000
|
174
|
+
nsecs_part = nanos % 1_000_000_000
|
175
|
+
Time.at secs_part, nsecs_part, :nanosecond
|
176
|
+
end
|
177
|
+
|
178
|
+
def normalize_exception exception
|
179
|
+
if exception.is_a?(::GRPC::Unavailable) && /Signet::AuthorizationError/ =~ exception.message
|
180
|
+
exception = Gapic::GRPC::AuthorizationError.new exception.message.gsub(%r{^\d+:}, "")
|
181
|
+
end
|
182
|
+
exception
|
183
|
+
end
|
184
|
+
|
185
|
+
def log_request request, metadata, try_number
|
186
|
+
return request unless @stub_logger
|
187
|
+
@stub_logger.info do |entry|
|
188
|
+
entry.set_system_name
|
189
|
+
entry.set_service
|
190
|
+
entry.set "rpcName", @method_name
|
191
|
+
entry.set "retryAttempt", try_number
|
192
|
+
entry.set "requestId", @request_id
|
193
|
+
entry.message =
|
194
|
+
if request.is_a? Enumerable
|
195
|
+
"Sending stream to #{entry.service}.#{@method_name} (try #{try_number})"
|
196
|
+
else
|
197
|
+
"Sending request to #{entry.service}.#{@method_name} (try #{try_number})"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
loggable_metadata = metadata.to_h rescue {}
|
201
|
+
if request.is_a? Enumerable
|
202
|
+
request.lazy.map do |req|
|
203
|
+
log_single_request req, loggable_metadata
|
204
|
+
end
|
205
|
+
else
|
206
|
+
log_single_request request, loggable_metadata
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def log_single_request request, metadata
|
211
|
+
request_content = request.respond_to?(:to_h) ? (request.to_h rescue {}) : request.to_s
|
212
|
+
if !request_content.empty? || !metadata.empty?
|
213
|
+
@stub_logger.debug do |entry|
|
214
|
+
entry.set "requestId", @request_id
|
215
|
+
entry.set "request", request_content
|
216
|
+
entry.set "headers", metadata
|
217
|
+
entry.message = "(request payload as #{request.class})"
|
218
|
+
end
|
219
|
+
end
|
220
|
+
request
|
221
|
+
end
|
222
|
+
|
223
|
+
def log_response response, try_number
|
224
|
+
return response unless @stub_logger
|
225
|
+
@stub_logger.info do |entry|
|
226
|
+
entry.set_system_name
|
227
|
+
entry.set_service
|
228
|
+
entry.set "rpcName", @method_name
|
229
|
+
entry.set "retryAttempt", try_number
|
230
|
+
entry.set "requestId", @request_id
|
231
|
+
case response
|
232
|
+
when StandardError
|
233
|
+
entry.set "exception", response.to_s
|
234
|
+
entry.message = "Received error for #{entry.service}.#{@method_name} (try #{try_number}): #{response}"
|
235
|
+
when Enumerable
|
236
|
+
entry.message = "Receiving stream for #{entry.service}.#{@method_name} (try #{try_number})"
|
237
|
+
else
|
238
|
+
entry.message = "Received response for #{entry.service}.#{@method_name} (try #{try_number})"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
case response
|
242
|
+
when StandardError
|
243
|
+
response
|
244
|
+
when Enumerable
|
245
|
+
response.lazy.map do |resp|
|
246
|
+
log_single_response resp
|
247
|
+
end
|
248
|
+
else
|
249
|
+
log_single_response response
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def log_single_response response
|
254
|
+
response_content = response.respond_to?(:to_h) ? (response.to_h rescue {}) : response.to_s
|
255
|
+
unless response_content.empty?
|
256
|
+
@stub_logger.debug do |entry|
|
257
|
+
entry.set "requestId", @request_id
|
258
|
+
entry.set "response", response_content
|
259
|
+
entry.message = "(response payload as #{response.class})"
|
260
|
+
end
|
261
|
+
end
|
262
|
+
response
|
155
263
|
end
|
156
264
|
end
|
157
265
|
end
|
@@ -17,6 +17,7 @@ require "googleauth"
|
|
17
17
|
require "gapic/grpc/service_stub/rpc_call"
|
18
18
|
require "gapic/grpc/service_stub/channel"
|
19
19
|
require "gapic/grpc/service_stub/channel_pool"
|
20
|
+
require "gapic/logging_concerns"
|
20
21
|
require "gapic/universe_domain_concerns"
|
21
22
|
|
22
23
|
module Gapic
|
@@ -32,6 +33,7 @@ module Gapic
|
|
32
33
|
#
|
33
34
|
class ServiceStub
|
34
35
|
include UniverseDomainConcerns
|
36
|
+
include LoggingConcerns
|
35
37
|
|
36
38
|
attr_reader :grpc_stub
|
37
39
|
attr_reader :channel_pool
|
@@ -64,6 +66,9 @@ module Gapic
|
|
64
66
|
# be used for intercepting calls before they are executed Interceptors are an EXPERIMENTAL API.
|
65
67
|
# @param channel_pool_config [::Gapic::ServiceStub:ChannelPool::Configuration] The configuration for channel
|
66
68
|
# pool. This argument will raise error when `credentials` is provided as a `::GRPC::Core::Channel`.
|
69
|
+
# @param logger [Logger,:default,nil] An explicit logger to use, or one
|
70
|
+
# of the values `:default` (the default) to construct a default logger,
|
71
|
+
# or `nil` to disable logging explicitly.
|
67
72
|
#
|
68
73
|
def initialize grpc_stub_class,
|
69
74
|
credentials:,
|
@@ -72,13 +77,19 @@ module Gapic
|
|
72
77
|
universe_domain: nil,
|
73
78
|
channel_args: nil,
|
74
79
|
interceptors: nil,
|
75
|
-
channel_pool_config: nil
|
80
|
+
channel_pool_config: nil,
|
81
|
+
logger: :default
|
76
82
|
raise ArgumentError, "grpc_stub_class is required" if grpc_stub_class.nil?
|
77
83
|
|
78
84
|
setup_universe_domain universe_domain: universe_domain,
|
79
85
|
endpoint: endpoint,
|
80
86
|
endpoint_template: endpoint_template,
|
81
87
|
credentials: credentials
|
88
|
+
setup_logging logger: logger,
|
89
|
+
system_name: grpc_stub_class,
|
90
|
+
service: grpc_stub_class,
|
91
|
+
endpoint: self.endpoint,
|
92
|
+
client_id: object_id
|
82
93
|
|
83
94
|
@channel_pool = nil
|
84
95
|
@grpc_stub = nil
|
@@ -102,7 +113,7 @@ module Gapic
|
|
102
113
|
end
|
103
114
|
@channel_pool = ChannelPool.new grpc_stub_class, endpoint: endpoint, credentials: credentials,
|
104
115
|
channel_args: channel_args, interceptors: interceptors,
|
105
|
-
config: channel_pool_config
|
116
|
+
config: channel_pool_config, stub_logger: stub_logger
|
106
117
|
end
|
107
118
|
|
108
119
|
def create_grpc_stub grpc_stub_class, endpoint:, credentials:, channel_args: nil, interceptors: nil
|
@@ -201,7 +212,8 @@ module Gapic
|
|
201
212
|
#
|
202
213
|
def call_rpc method_name, request, options: nil, &block
|
203
214
|
if @channel_pool.nil?
|
204
|
-
|
215
|
+
meth = @grpc_stub.method method_name
|
216
|
+
rpc_call = RpcCall.new meth, stub_logger: stub_logger, method_name: method_name
|
205
217
|
rpc_call.call request, options: options, &block
|
206
218
|
else
|
207
219
|
@channel_pool.call_rpc method_name, request, options: options, &block
|
data/lib/gapic/headers.rb
CHANGED
@@ -19,6 +19,8 @@ require "gapic/common/version"
|
|
19
19
|
module Gapic
|
20
20
|
# A collection of common header values.
|
21
21
|
module Headers
|
22
|
+
# rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
23
|
+
|
22
24
|
##
|
23
25
|
# @param ruby_version [String] The ruby version. Defaults to `RUBY_VERSION`.
|
24
26
|
# @param lib_name [String] The client library name.
|
@@ -32,10 +34,10 @@ module Gapic
|
|
32
34
|
# `:grpc` to send the GRPC library version (if defined)
|
33
35
|
# `:rest` to send the REST library version (if defined)
|
34
36
|
# Defaults to `[:grpc]`
|
37
|
+
#
|
35
38
|
def self.x_goog_api_client ruby_version: nil, lib_name: nil, lib_version: nil, gax_version: nil,
|
36
39
|
gapic_version: nil, grpc_version: nil, rest_version: nil, protobuf_version: nil,
|
37
40
|
transports_version_send: [:grpc]
|
38
|
-
|
39
41
|
ruby_version ||= ::RUBY_VERSION
|
40
42
|
gax_version ||= ::Gapic::Common::VERSION
|
41
43
|
grpc_version ||= ::GRPC::VERSION if defined? ::GRPC::VERSION
|
@@ -52,4 +54,6 @@ module Gapic
|
|
52
54
|
x_goog_api_client_header.join " ".freeze
|
53
55
|
end
|
54
56
|
end
|
57
|
+
|
58
|
+
# rubocop:enable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
55
59
|
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
# Copyright 2024 Google LLC
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require "google/cloud/env"
|
16
|
+
require "google/logging/message"
|
17
|
+
require "google/logging/structured_formatter"
|
18
|
+
|
19
|
+
module Gapic
|
20
|
+
##
|
21
|
+
# A mixin module that handles logging setup for a stub.
|
22
|
+
#
|
23
|
+
module LoggingConcerns
|
24
|
+
##
|
25
|
+
# The logger for this object.
|
26
|
+
#
|
27
|
+
# @return [Logger]
|
28
|
+
#
|
29
|
+
attr_reader :logger
|
30
|
+
|
31
|
+
##
|
32
|
+
# @private
|
33
|
+
# A convenience object used by stub-based logging.
|
34
|
+
#
|
35
|
+
class StubLogger
|
36
|
+
OMIT_FILES = [
|
37
|
+
/^#{Regexp.escape __dir__}/
|
38
|
+
].freeze
|
39
|
+
|
40
|
+
def initialize logger: nil, **kwargs
|
41
|
+
@logger = logger
|
42
|
+
@kwargs = kwargs
|
43
|
+
end
|
44
|
+
|
45
|
+
def log severity
|
46
|
+
return unless @logger
|
47
|
+
locations = caller_locations
|
48
|
+
@logger.add severity do
|
49
|
+
builder = LogEntryBuilder.new(**@kwargs)
|
50
|
+
builder.set_source_location_from locations
|
51
|
+
yield builder
|
52
|
+
builder.build
|
53
|
+
rescue StandardError
|
54
|
+
# Do nothing
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def info &block
|
59
|
+
log Logger::INFO, &block
|
60
|
+
end
|
61
|
+
|
62
|
+
def debug &block
|
63
|
+
log Logger::DEBUG, &block
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# @private
|
68
|
+
# Builder for a log entry, passed to {StubLogger#log}.
|
69
|
+
#
|
70
|
+
class LogEntryBuilder
|
71
|
+
def initialize system_name: nil,
|
72
|
+
service: nil,
|
73
|
+
endpoint: nil,
|
74
|
+
client_id: nil
|
75
|
+
@system_name = system_name
|
76
|
+
@service = service
|
77
|
+
@endpoint = endpoint
|
78
|
+
@client_id = client_id
|
79
|
+
@message = nil
|
80
|
+
@caller_locations = caller_locations
|
81
|
+
@fields = { "clientId" => @client_id }
|
82
|
+
end
|
83
|
+
|
84
|
+
attr_reader :system_name
|
85
|
+
|
86
|
+
attr_reader :service
|
87
|
+
|
88
|
+
attr_reader :endpoint
|
89
|
+
|
90
|
+
attr_accessor :message
|
91
|
+
|
92
|
+
attr_writer :source_location
|
93
|
+
|
94
|
+
attr_reader :fields
|
95
|
+
|
96
|
+
def set name, value
|
97
|
+
fields[name] = value
|
98
|
+
end
|
99
|
+
|
100
|
+
def set_system_name
|
101
|
+
set "system", system_name
|
102
|
+
end
|
103
|
+
|
104
|
+
def set_service
|
105
|
+
set "serviceName", service
|
106
|
+
end
|
107
|
+
|
108
|
+
def set_credentials_fields creds
|
109
|
+
creds = creds.client if creds.respond_to? :client
|
110
|
+
set "credentialsId", creds.object_id
|
111
|
+
set "credentialsType", creds.class.name
|
112
|
+
set "credentialsScope", creds.scope if creds.respond_to? :scope
|
113
|
+
set "useSelfSignedJWT", creds.enable_self_signed_jwt? if creds.respond_to? :enable_self_signed_jwt?
|
114
|
+
set "universeDomain", creds.universe_domain if creds.respond_to? :universe_domain
|
115
|
+
end
|
116
|
+
|
117
|
+
def source_location
|
118
|
+
@source_location ||= Google::Logging::SourceLocation.for_caller omit_files: OMIT_FILES,
|
119
|
+
locations: @caller_locations
|
120
|
+
end
|
121
|
+
|
122
|
+
def set_source_location_from locations
|
123
|
+
@caller_locations = locations
|
124
|
+
@source_location = nil
|
125
|
+
end
|
126
|
+
|
127
|
+
def build
|
128
|
+
Google::Logging::Message.from message: message, source_location: source_location, fields: fields
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# @private
|
135
|
+
# Initialize logging concerns.
|
136
|
+
#
|
137
|
+
def setup_logging logger: :default,
|
138
|
+
stream: nil,
|
139
|
+
formatter: nil,
|
140
|
+
level: nil,
|
141
|
+
system_name: nil,
|
142
|
+
service: nil,
|
143
|
+
endpoint: nil,
|
144
|
+
client_id: nil
|
145
|
+
service = LoggingConcerns.normalize_service service
|
146
|
+
system_name = LoggingConcerns.normalize_system_name system_name
|
147
|
+
logging_env = ENV["GOOGLE_SDK_RUBY_LOGGING_GEMS"].to_s.downcase
|
148
|
+
logger = nil if ["false", "none"].include? logging_env
|
149
|
+
if logger == :default
|
150
|
+
logger = nil
|
151
|
+
if ["true", "all"].include?(logging_env) || logging_env.split(",").include?(system_name)
|
152
|
+
stream ||= $stderr
|
153
|
+
level ||= "DEBUG"
|
154
|
+
formatter ||= Google::Logging::StructuredFormatter.new if Google::Cloud::Env.get.logging_agent_expected?
|
155
|
+
logger = Logger.new stream, progname: system_name, level: level, formatter: formatter
|
156
|
+
end
|
157
|
+
end
|
158
|
+
@logger = logger
|
159
|
+
@stub_logger = StubLogger.new logger: logger,
|
160
|
+
system_name: system_name,
|
161
|
+
service: service,
|
162
|
+
endpoint: endpoint,
|
163
|
+
client_id: client_id
|
164
|
+
end
|
165
|
+
|
166
|
+
# @private
|
167
|
+
attr_reader :stub_logger
|
168
|
+
|
169
|
+
class << self
|
170
|
+
# @private
|
171
|
+
def random_uuid4
|
172
|
+
ary = Random.bytes 16
|
173
|
+
ary.setbyte 6, ((ary.getbyte(6) & 0x0f) | 0x40)
|
174
|
+
ary.setbyte 8, ((ary.getbyte(8) & 0x3f) | 0x80)
|
175
|
+
ary.unpack("H8H4H4H4H12").join "-"
|
176
|
+
end
|
177
|
+
|
178
|
+
# @private
|
179
|
+
def normalize_system_name input
|
180
|
+
case input
|
181
|
+
when String
|
182
|
+
input
|
183
|
+
when Class
|
184
|
+
input.name.split("::")[..-3]
|
185
|
+
.map { |elem| elem.scan(/[A-Z][A-Z]*(?=[A-Z][a-z0-9]|$)|[A-Z][a-z0-9]+/).map(&:downcase).join("_") }
|
186
|
+
.join("-")
|
187
|
+
else
|
188
|
+
"googleapis"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# @private
|
193
|
+
def normalize_service input
|
194
|
+
case input
|
195
|
+
when String
|
196
|
+
input
|
197
|
+
when Class
|
198
|
+
mod = input.name.split("::")[..-2].inject(Object) { |m, n| m.const_get n }
|
199
|
+
if mod.const_defined? "Service"
|
200
|
+
mod.const_get("Service").service_name
|
201
|
+
else
|
202
|
+
name_segments = input.name.split("::")[..-3]
|
203
|
+
mod = name_segments.inject(Object) { |m, n| m.const_get n }
|
204
|
+
name_segments.join "." if mod.const_defined? "Rest"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
@@ -12,80 +12,40 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
require "gapic/common/retry_policy"
|
16
|
+
|
15
17
|
module Gapic
|
16
18
|
class Operation
|
17
19
|
##
|
18
|
-
# The policy for retrying operation reloads using an incremental backoff.
|
19
|
-
#
|
20
|
+
# The policy for retrying operation reloads using an incremental backoff.
|
21
|
+
#
|
22
|
+
# A new object instance should be used for every Operation invocation.
|
20
23
|
#
|
21
|
-
class RetryPolicy
|
24
|
+
class RetryPolicy < Gapic::Common::RetryPolicy
|
25
|
+
# @return [Numeric] Default initial delay in seconds.
|
26
|
+
DEFAULT_INITIAL_DELAY = 10
|
27
|
+
# @return [Numeric] Default maximum delay in seconds.
|
28
|
+
DEFAULT_MAX_DELAY = 300 # Five minutes
|
29
|
+
# @return [Numeric] Default delay scaling factor for subsequent retry attempts.
|
30
|
+
DEFAULT_MULTIPLIER = 1.3
|
31
|
+
# @return [Numeric] Default timeout threshold value in seconds.
|
32
|
+
DEFAULT_TIMEOUT = 3600 # One hour
|
33
|
+
|
22
34
|
##
|
23
35
|
# Create new Operation RetryPolicy.
|
24
36
|
#
|
25
|
-
# @param initial_delay [Numeric]
|
26
|
-
# @param multiplier [Numeric]
|
27
|
-
# @param max_delay [Numeric]
|
28
|
-
# @param timeout [Numeric]
|
37
|
+
# @param initial_delay [Numeric] Initial delay in seconds.
|
38
|
+
# @param multiplier [Numeric] The delay scaling factor for each subsequent retry attempt.
|
39
|
+
# @param max_delay [Numeric] Maximum delay in seconds.
|
40
|
+
# @param timeout [Numeric] Timeout threshold value in seconds.
|
29
41
|
#
|
30
42
|
def initialize initial_delay: nil, multiplier: nil, max_delay: nil, timeout: nil
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
def initial_delay
|
39
|
-
@initial_delay || 10
|
40
|
-
end
|
41
|
-
|
42
|
-
def multiplier
|
43
|
-
@multiplier || 1.3
|
44
|
-
end
|
45
|
-
|
46
|
-
def max_delay
|
47
|
-
@max_delay || 300 # Five minutes
|
48
|
-
end
|
49
|
-
|
50
|
-
def timeout
|
51
|
-
@timeout || 3600 # One hour
|
52
|
-
end
|
53
|
-
|
54
|
-
def call
|
55
|
-
return unless retry?
|
56
|
-
|
57
|
-
delay!
|
58
|
-
increment_delay!
|
59
|
-
|
60
|
-
true
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
|
65
|
-
def deadline
|
66
|
-
# memoize the deadline
|
67
|
-
@deadline ||= Time.now + timeout
|
68
|
-
end
|
69
|
-
|
70
|
-
def retry?
|
71
|
-
deadline > Time.now
|
72
|
-
end
|
73
|
-
|
74
|
-
##
|
75
|
-
# The current delay value.
|
76
|
-
def delay
|
77
|
-
@delay || initial_delay
|
78
|
-
end
|
79
|
-
|
80
|
-
def delay!
|
81
|
-
# Call Kernel.sleep so we can stub it.
|
82
|
-
Kernel.sleep delay
|
83
|
-
end
|
84
|
-
|
85
|
-
##
|
86
|
-
# Calculate and set the next delay value.
|
87
|
-
def increment_delay!
|
88
|
-
@delay = [delay * multiplier, max_delay].min
|
43
|
+
super(
|
44
|
+
initial_delay: initial_delay || DEFAULT_INITIAL_DELAY,
|
45
|
+
max_delay: max_delay || DEFAULT_MAX_DELAY,
|
46
|
+
multiplier: multiplier || DEFAULT_MULTIPLIER,
|
47
|
+
timeout: timeout || DEFAULT_TIMEOUT
|
48
|
+
)
|
89
49
|
end
|
90
50
|
end
|
91
51
|
end
|