statelydb 0.1.1 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/common/net/conn.rb +9 -1
- data/lib/error.rb +21 -10
- data/lib/stately_codes.rb +79 -0
- data/lib/statelydb.rb +4 -1
- data/lib/transaction/transaction.rb +12 -2
- data/lib/uuid.rb +16 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d085f703fae0e0d968fe62788d74409d67b487025c76eca89589ded2b985794f
|
4
|
+
data.tar.gz: 3f9a0a0e029cb375f970eb2acfea662aced22501302758eedd5c7938ae6ebe26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fac13f5e528c452d3a69f305cfef78e34374f58913125a2ac9291656427ff8895ff303baa29c4244150b1e69dadf8bbadc13520bb02297de34c8e38801da35bc
|
7
|
+
data.tar.gz: 2c2f9ee717d50aef99d135c1316e7c3947617592246122461888b2bbb111c3f3204f9677fbef3cf8f33c1e5d04cecb1a4fecbfa99aaa44a772138e79b1663257
|
data/lib/common/net/conn.rb
CHANGED
@@ -19,7 +19,15 @@ module StatelyDB
|
|
19
19
|
else
|
20
20
|
creds.compose(call_creds)
|
21
21
|
end
|
22
|
-
GRPC::Core::Channel.new(endpoint_uri.authority, {
|
22
|
+
GRPC::Core::Channel.new(endpoint_uri.authority, {
|
23
|
+
# 2x the default of 8kb = 16kb
|
24
|
+
# Set max and absolute max to the same value
|
25
|
+
# to stop the grpc lib changing the error code to ResourceExhausted
|
26
|
+
# while still successfully reading the metadata because only the soft
|
27
|
+
# limit was exceeded.
|
28
|
+
"grpc.max_metadata_size" => 8192 * 2,
|
29
|
+
"grpc.absolute_max_metadata_size" => 8192 * 2
|
30
|
+
}, creds)
|
23
31
|
end
|
24
32
|
end
|
25
33
|
end
|
data/lib/error.rb
CHANGED
@@ -22,14 +22,7 @@ module StatelyDB
|
|
22
22
|
# @param [String] stately_code
|
23
23
|
# @param [Exception] cause
|
24
24
|
def initialize(message, code: nil, stately_code: nil, cause: nil)
|
25
|
-
|
26
|
-
code_str = if code > 0
|
27
|
-
GRPC::Core::StatusCodes.constants.find do |c|
|
28
|
-
GRPC::Core::StatusCodes.const_get(c) === code
|
29
|
-
end.to_s.split("_").collect(&:capitalize).join
|
30
|
-
else
|
31
|
-
"Unknown"
|
32
|
-
end
|
25
|
+
code_str = self.class.grpc_code_to_string(code)
|
33
26
|
|
34
27
|
super("(#{code_str}/#{stately_code}): #{message}")
|
35
28
|
@code = code
|
@@ -50,13 +43,31 @@ module StatelyDB
|
|
50
43
|
raw_detail = status.details[0]
|
51
44
|
if raw_detail.type_url == "type.googleapis.com/stately.errors.StatelyErrorDetails"
|
52
45
|
error_details = Stately::Errors::StatelyErrorDetails.decode(raw_detail.value)
|
46
|
+
upstream_cause = error_details.upstream_cause.empty? ? nil : StandardError.new(error_details.upstream_cause) # rubocop:disable Metrics/BlockNesting
|
53
47
|
return new(error_details.message, code: error.code, stately_code: error_details.stately_code,
|
54
|
-
cause:
|
48
|
+
cause: upstream_cause)
|
55
49
|
end
|
56
50
|
end
|
57
51
|
end
|
58
52
|
|
59
|
-
new(error.message, code: GRPC::
|
53
|
+
new(error.message, code: GRPC::Core::StatusCodes::UNKNOWN, stately_code: "Unknown", cause: error)
|
54
|
+
end
|
55
|
+
|
56
|
+
def code_string
|
57
|
+
self.class.grpc_code_to_string(@code)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Turn a gRPC status code into a human-readable string. e.g. 3 -> "InvalidArgument"
|
61
|
+
# @param [Integer] code
|
62
|
+
# @return [String]
|
63
|
+
def self.grpc_code_to_string(code)
|
64
|
+
if code > 0
|
65
|
+
GRPC::Core::StatusCodes.constants.find do |c|
|
66
|
+
GRPC::Core::StatusCodes.const_get(c) === code
|
67
|
+
end.to_s.split("_").collect(&:capitalize).join
|
68
|
+
else
|
69
|
+
"Unknown"
|
70
|
+
end
|
60
71
|
end
|
61
72
|
end
|
62
73
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module StatelyCode
|
4
|
+
# StoreRequestLimitExceeded indicates that an attempt to modify a Store has
|
5
|
+
# been temporarily rejected due to exceeding global modification limits.
|
6
|
+
# StatelyDB has been notified about this error and will take necessary
|
7
|
+
# actions to correct it. In the event that the issue has not been resolved,
|
8
|
+
# please contact support.
|
9
|
+
#
|
10
|
+
# - Retryable? Yes.
|
11
|
+
STORE_REQUEST_LIMIT_EXCEEDED = "StoreRequestLimitExceeded"
|
12
|
+
|
13
|
+
# StoreThroughputExceeded indicates that the underlying Store does not have
|
14
|
+
# resources to complete the request. This may indicate a request rate is too
|
15
|
+
# high to a specific Group or that a sudden burst of traffic has exceeded a
|
16
|
+
# Store's provisioned capacity.
|
17
|
+
#
|
18
|
+
# - Retryable? Yes.
|
19
|
+
# With an exponential backoff.
|
20
|
+
STORE_THROUGHPUT_EXCEEDED = "StoreThroughputExceeded"
|
21
|
+
|
22
|
+
# ConditionalCheckFailed indicates that conditions provided to perform an
|
23
|
+
# operation were not met. For example, a condition to write an item only if
|
24
|
+
# it does not already exist. In the future StatelyDB may provide more
|
25
|
+
# information about the failed condition; if this feature is a blocker,
|
26
|
+
# please contact support.
|
27
|
+
#
|
28
|
+
# - Retryable? No.
|
29
|
+
# Typically a conditional check failure is not retryable
|
30
|
+
# unless the conditions for the operation are changed.
|
31
|
+
CONDITIONAL_CHECK_FAILED = "ConditionalCheckFailed"
|
32
|
+
|
33
|
+
# NonRecoverableTransaction indicates that conditions required for the
|
34
|
+
# transaction to succeed are not possible to meet with the current state of
|
35
|
+
# the system. This can occur when an Item has more than one key-path, and is
|
36
|
+
# written with a "must not exist" condition (e.g. with ID Generation on one
|
37
|
+
# of the keys) but another keys already maps to an existing item in the
|
38
|
+
# store. Permitting such a write would result in conflicting state; two
|
39
|
+
# independent records with aliases pointing to the same item.
|
40
|
+
#
|
41
|
+
# - Retryable? No.
|
42
|
+
NON_RECOVERABLE_TRANSACTION = "NonRecoverableTransaction"
|
43
|
+
|
44
|
+
# ConcurrentModification indicates the current transaction was aborted
|
45
|
+
# because of a non-serializable interaction with another transaction was
|
46
|
+
# detected, a stale read was detected, or because attempts to resolve an
|
47
|
+
# otherwise serializable interaction have exceeded the maximum number of
|
48
|
+
# internal resolution retries. Examples:
|
49
|
+
#
|
50
|
+
# 1. TransactionA and TransactionB are opened concurrently. TransactionA
|
51
|
+
# reads ItemX, puts ItemY. Before transactionA can commit, transactionB
|
52
|
+
# writes ItemX and commits. When transactionA tries to commit, it will fail
|
53
|
+
# with ConcurrentModification because the read of ItemX in transactionA is
|
54
|
+
# no longer valid. That is, the data in ItemX which leads to the decision to
|
55
|
+
# put ItemY may have changed, and thus a conflict is detected.
|
56
|
+
#
|
57
|
+
# 2. TransactionA is opened which writes ItemA with an initialValue field (a
|
58
|
+
# field used for ID assignment) -- the generated ID is returned to the
|
59
|
+
# client. transactionB also performs a on an item which resolves to the same
|
60
|
+
# initialValue, transactionB is committed first. Since transactionA may have
|
61
|
+
# acted on the generatedID (e.g. written in a different record), it will be
|
62
|
+
# aborted because the ID is no longer valid for the item it was intended
|
63
|
+
# for.
|
64
|
+
#
|
65
|
+
# 3. A read or list operation detected that underlying data has changed
|
66
|
+
# since the transaction began.
|
67
|
+
#
|
68
|
+
# - Retryable? Yes.
|
69
|
+
# This error is immediately retryable.
|
70
|
+
CONCURRENT_MODIFICATION = "ConcurrentModification"
|
71
|
+
|
72
|
+
# StoreInUse indicates that the underlying Store is currently in being
|
73
|
+
# updated and cannot be modified until the operation in progress has
|
74
|
+
# completed.
|
75
|
+
#
|
76
|
+
# - Retryable? Yes.
|
77
|
+
# This can be retried with backoff.
|
78
|
+
STORE_IN_USE = "StoreInUse"
|
79
|
+
end
|
data/lib/statelydb.rb
CHANGED
@@ -240,8 +240,11 @@ module StatelyDB
|
|
240
240
|
rescue Exception => e
|
241
241
|
txn.abort
|
242
242
|
|
243
|
+
# All gRPC errors inherit from GRPC::BadStatus. We wrap these in a StatelyDB::Error.
|
244
|
+
raise StatelyDB::Error.from(e) if e.is_a? GRPC::BadStatus
|
245
|
+
|
243
246
|
# Calling raise with no parameters re-raises the original exception
|
244
|
-
raise
|
247
|
+
raise
|
245
248
|
end
|
246
249
|
|
247
250
|
private
|
@@ -239,7 +239,7 @@ module StatelyDB
|
|
239
239
|
# for the items will be returned while inside the transaction block.
|
240
240
|
#
|
241
241
|
# @param items [StatelyDB::Item, Array<StatelyDB::Item>] the items to store
|
242
|
-
# @return [Array<String>] the
|
242
|
+
# @return [Array<StatelyDB::UUID, String, Integer, nil>] the ids of the items
|
243
243
|
#
|
244
244
|
# @example
|
245
245
|
# results = client.data.transaction do |txn|
|
@@ -261,7 +261,17 @@ module StatelyDB
|
|
261
261
|
)
|
262
262
|
|
263
263
|
resp = request_response(req).put_ack
|
264
|
-
resp.generated_ids.map
|
264
|
+
resp.generated_ids.map do |generated_id|
|
265
|
+
case generated_id.value
|
266
|
+
when :bytes
|
267
|
+
StatelyDB::UUID.valid_uuid?(generated_id.bytes) ? StatelyDB::UUID.parse(generated_id.bytes) : generated_id.bytes
|
268
|
+
when :uint
|
269
|
+
generated_id.uint
|
270
|
+
else # rubocop:disable Style/EmptyElse
|
271
|
+
# An empty identifier is sent in the transaction Put response if an initialValue is not set
|
272
|
+
nil
|
273
|
+
end
|
274
|
+
end
|
265
275
|
end
|
266
276
|
|
267
277
|
# Delete one or more Items from a StatelyDB Store at the given key_paths. Results are not returned until the transaction is
|
data/lib/uuid.rb
CHANGED
@@ -48,6 +48,12 @@ module StatelyDB
|
|
48
48
|
to_s <=> other.to_s
|
49
49
|
end
|
50
50
|
|
51
|
+
# Returns true if the UUID is empty.
|
52
|
+
# @return [Boolean]
|
53
|
+
def empty?
|
54
|
+
@byte_string.empty?
|
55
|
+
end
|
56
|
+
|
51
57
|
# Parses a base16 string (eg: "f4a8a24a-129d-411f-91d2-6d19d0eaa096") into a UUID object.
|
52
58
|
# The string can be the following:
|
53
59
|
# 1. Encoded as Encoding::ASCII_8BIT (also aliased as Encoding::BINARY) and be 16 bytes long.
|
@@ -56,7 +62,9 @@ module StatelyDB
|
|
56
62
|
# base16-formatted UUID string.
|
57
63
|
# @return [StatelyDB::UUID]
|
58
64
|
def self.parse(byte_string)
|
59
|
-
|
65
|
+
return byte_string if byte_string.is_a?(StatelyDB::UUID)
|
66
|
+
|
67
|
+
if valid_uuid?(byte_string)
|
60
68
|
return new(byte_string)
|
61
69
|
elsif byte_string.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)
|
62
70
|
return new([byte_string.delete("-")].pack("H*"))
|
@@ -64,5 +72,12 @@ module StatelyDB
|
|
64
72
|
|
65
73
|
raise "Invalid UUID"
|
66
74
|
end
|
75
|
+
|
76
|
+
# Not all bytes values in StatelyDB are UUIDs. This method checks if a byte string is a valid UUID.
|
77
|
+
# @param [String] byte_string A binary-encoded string (eg: Encoding::ASCII_8BIT encoding)
|
78
|
+
# @return [Boolean]
|
79
|
+
def self.valid_uuid?(byte_string)
|
80
|
+
byte_string.encoding == Encoding::BINARY && byte_string.bytesize == 16
|
81
|
+
end
|
67
82
|
end
|
68
83
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statelydb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stately Cloud, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async
|
@@ -79,6 +79,7 @@ files:
|
|
79
79
|
- lib/common/net/conn.rb
|
80
80
|
- lib/error.rb
|
81
81
|
- lib/key_path.rb
|
82
|
+
- lib/stately_codes.rb
|
82
83
|
- lib/statelydb.rb
|
83
84
|
- lib/token.rb
|
84
85
|
- lib/transaction/queue.rb
|