google-cloud-spanner 2.1.0 → 2.2.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
  SHA256:
3
- metadata.gz: d7eb1575c3244eb459d8379345e2dea6f19c925bbeb526ff969aa07a34428c94
4
- data.tar.gz: 9c8c0b2d99074ec99ff38125ccbf89713f0d7c5441445650b96b5a969b09629a
3
+ metadata.gz: 01dd371ff37296529b691fd13961d7e7681e63480a88202b9e958a8c28bc480b
4
+ data.tar.gz: 9915fdf52be7508c55380b193a9586a35c702617080d3bf93a9f53b37b62be84
5
5
  SHA512:
6
- metadata.gz: ba900cc5a539d55baead3d8825472b05b40ab19adc3062dfb93c7cf1713805b9619c2cbd7b115f3e2e61f79371e4c53eb8a225f8cd1f7a3dc1c30f72e1590cc7
7
- data.tar.gz: 1639fd79b6bd30af238b2d002852bec94e4f29aa581594758169180e15e6b335f86c5a6cac1fa9a13a7fef02edc105ea46eb4867a02c59bf0a069c142d8799e2
6
+ metadata.gz: 0a34c4eeaaf84abe4d311350a155b22190c7dbc426a48719df4ad553692d841aa1a2d3a72d7f043b2fef7b3fa87a81cda69f965f5eef58a8ce17a77bf186a48e
7
+ data.tar.gz: 36062397079b8960916575b9188c0ad10f376d27b7d194a20e7f4c6e69f29eeb018b499576209bf1b2d2985725233db5de3e233ff840b5c93790d15b9b4204ab
@@ -1,5 +1,16 @@
1
1
  # Release History
2
2
 
3
+ ### 2.2.0 / 2020-09-15
4
+
5
+ #### Features
6
+
7
+ * quota_project can be set via library configuration
8
+ * Support numeric type.
9
+
10
+ #### Bug Fixes
11
+
12
+ * retry or resume eos and rst_stream errors
13
+
3
14
  ### 2.1.0 / 2020-08-05
4
15
 
5
16
  #### Features
@@ -174,6 +174,7 @@ Google::Cloud.configure.add_config! :spanner do |config|
174
174
  allow_nil: true
175
175
  config.add_alias! :keyfile, :credentials
176
176
  config.add_field! :scope, default_scopes, match: [String, Array]
177
+ config.add_field! :quota_project, nil, match: String
177
178
  config.add_field! :timeout, nil, match: Integer
178
179
  config.add_field! :endpoint, "spanner.googleapis.com", match: String
179
180
  config.add_field! :emulator_host, default_emulator, match: String, allow_nil: true
@@ -17,6 +17,7 @@ require "time"
17
17
  require "date"
18
18
  require "stringio"
19
19
  require "base64"
20
+ require "bigdecimal"
20
21
  require "google/cloud/spanner/data"
21
22
 
22
23
  module Google
@@ -67,6 +68,9 @@ module Google
67
68
  Google::Protobuf::Value.new bool_value: false
68
69
  when Integer
69
70
  Google::Protobuf::Value.new string_value: obj.to_s
71
+ # BigDecimal must be put before Numeric.
72
+ when BigDecimal
73
+ Google::Protobuf::Value.new string_value: obj.to_s("F")
70
74
  when Numeric
71
75
  if obj == Float::INFINITY
72
76
  Google::Protobuf::Value.new string_value: "Infinity"
@@ -125,6 +129,9 @@ module Google
125
129
  :BOOL
126
130
  when Integer
127
131
  :INT64
132
+ # BigDecimal must be put before Numeric.
133
+ when BigDecimal
134
+ :NUMERIC
128
135
  when Numeric
129
136
  :FLOAT64
130
137
  when Time
@@ -214,6 +221,8 @@ module Google
214
221
  end
215
222
  when :STRUCT
216
223
  Data.from_grpc value.list_value.values, type.struct_type.fields
224
+ when :NUMERIC
225
+ BigDecimal value.string_value
217
226
  end
218
227
  end
219
228
 
@@ -41,6 +41,8 @@ module Google
41
41
  # end
42
42
  #
43
43
  class Results
44
+ RST_STREAM_INTERNAL_ERROR = "Received RST_STREAM".freeze
45
+ EOS_INTERNAL_ERROR = "Received unexpected EOS on DATA frame from server".freeze
44
46
  ##
45
47
  # The read timestamp chosen for single-use snapshots (read-only
46
48
  # transactions).
@@ -107,12 +109,24 @@ module Google
107
109
  buffer_upper_bound = 10
108
110
  chunked_value = nil
109
111
  resume_token = nil
112
+ should_resume_request = false
113
+ should_retry_request = false
110
114
 
111
115
  # Cannot call Enumerator#each because it won't return the first
112
116
  # value that was already identified when calling Enumerator#peek.
113
117
  # Iterate only using Enumerator#next and break on StopIteration.
114
118
  loop do
115
119
  begin
120
+ if should_resume_request
121
+ @enum = resume_request(resume_token)
122
+ buffered_responses = []
123
+ should_resume_request = false
124
+ elsif should_retry_request
125
+ @enum = retry_request()
126
+ buffered_responses = []
127
+ should_retry_request = false
128
+ end
129
+
116
130
  grpc = @enum.next
117
131
  # metadata should be set before the first iteration...
118
132
  @metadata ||= grpc.metadata
@@ -143,28 +157,36 @@ module Google
143
157
  # Flush the buffered responses now that they are all handled
144
158
  buffered_responses = []
145
159
  end
146
- rescue GRPC::Cancelled, GRPC::DeadlineExceeded, GRPC::Internal,
147
- GRPC::ResourceExhausted, GRPC::Unauthenticated,
148
- GRPC::Unavailable, GRPC::Core::CallError => err
149
- if resume_token.nil? || resume_token.empty?
150
- # Re-raise if the resume_token is not a valid value.
151
- # This can happen if the buffer was flushed.
152
- raise Google::Cloud::Error.from_error(err)
153
- end
160
+ # TODO: once the generated client throws only Google Cloud errors, remove
161
+ # the GRPC errors from the rescue block
162
+ rescue GRPC::Aborted,
163
+ GRPC::Cancelled,
164
+ GRPC::DeadlineExceeded,
165
+ GRPC::Internal,
166
+ GRPC::ResourceExhausted,
167
+ GRPC::Unauthenticated,
168
+ GRPC::Unavailable,
169
+ GRPC::Core::CallError,
170
+ Google::Cloud::AbortedError,
171
+ Google::Cloud::CanceledError,
172
+ Google::Cloud::DeadlineExceededError,
173
+ Google::Cloud::InternalError,
174
+ Google::Cloud::ResourceExhaustedError,
175
+ Google::Cloud::UnauthenticatedError,
176
+ Google::Cloud::UnavailableError => err
154
177
 
155
- # Resume the stream from the last known resume_token
156
- if @execute_query_options
157
- @enum = @service.execute_streaming_sql \
158
- @session_path, @sql,
159
- @execute_query_options.merge(resume_token: resume_token)
178
+ if resumable?(resume_token)
179
+ should_resume_request = true
180
+ elsif retryable?(err)
181
+ should_retry_request = true
182
+ elsif err.is_a?(Google::Cloud::Error)
183
+ raise err
160
184
  else
161
- @enum = @service.streaming_read_table \
162
- @session_path, @table, @columns,
163
- @read_options.merge(resume_token: resume_token)
185
+ raise Google::Cloud::Error.from_error(err)
164
186
  end
165
187
 
166
- # Flush the buffered responses to reset to the resume_token
167
- buffered_responses = []
188
+ # TODO: once the generated client throws only Google Cloud errors, remove
189
+ # this rescue block (for GRPC::BadStatus)
168
190
  rescue GRPC::BadStatus => err
169
191
  raise Google::Cloud::Error.from_error(err)
170
192
  rescue StopIteration
@@ -198,6 +220,60 @@ module Google
198
220
 
199
221
  # rubocop:enable all
200
222
 
223
+ ##
224
+ # @private
225
+ # Checks if a request can be resumed by inspecting the resume token
226
+ def resumable? resume_token
227
+ resume_token && !resume_token.empty?
228
+ end
229
+
230
+ ##
231
+ # @private
232
+ # Checks if a request can be retried. This is based on the error returned.
233
+ # Retryable errors are:
234
+ # - Unavailable error
235
+ # - Internal EOS error
236
+ # - Internal RST_STREAM error
237
+ def retryable? err
238
+ err.instance_of?(Google::Cloud::UnavailableError) ||
239
+ err.instance_of?(GRPC::Unavailable) ||
240
+ (err.instance_of?(Google::Cloud::InternalError) && err.message.include?(EOS_INTERNAL_ERROR)) ||
241
+ (err.instance_of?(GRPC::Internal) && err.details.include?(EOS_INTERNAL_ERROR)) ||
242
+ (err.instance_of?(Google::Cloud::InternalError) && err.message.include?(RST_STREAM_INTERNAL_ERROR)) ||
243
+ (err.instance_of?(GRPC::Internal) && err.details.include?(RST_STREAM_INTERNAL_ERROR))
244
+ end
245
+
246
+ ##
247
+ # @private
248
+ # Resumes a request, by re-executing it with a resume token.
249
+ def resume_request resume_token
250
+ if @execute_query_options
251
+ @service.execute_streaming_sql(
252
+ @session_path,
253
+ @sql,
254
+ @execute_query_options.merge(resume_token: resume_token)
255
+ )
256
+ else
257
+ @service.streaming_read_table(
258
+ @session_path,
259
+ @table,
260
+ @columns,
261
+ @read_options.merge(resume_token: resume_token)
262
+ )
263
+ end
264
+ end
265
+
266
+ ##
267
+ # @private
268
+ # Retries a request, by re-executing it from scratch.
269
+ def retry_request
270
+ if @execute_query_options
271
+ @service.execute_streaming_sql @session_path, @sql, @execute_query_options
272
+ else
273
+ @service.streaming_read_table @session_path, @table, @columns, @read_options
274
+ end
275
+ end
276
+
201
277
  ##
202
278
  # @private
203
279
  # Get row count from stats. This will be the exact row count for DML
@@ -16,7 +16,7 @@
16
16
  module Google
17
17
  module Cloud
18
18
  module Spanner
19
- VERSION = "2.1.0".freeze
19
+ VERSION = "2.2.0".freeze
20
20
  end
21
21
  end
22
22
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-cloud-spanner
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Moore
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-08-06 00:00:00.000000000 Z
12
+ date: 2020-09-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: google-cloud-core
@@ -329,7 +329,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
329
329
  - !ruby/object:Gem::Version
330
330
  version: '0'
331
331
  requirements: []
332
- rubygems_version: 3.1.3
332
+ rubygems_version: 3.1.4
333
333
  signing_key:
334
334
  specification_version: 4
335
335
  summary: API Client library for Google Cloud Spanner API