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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5716a868b12a20de48e33bddf16396bac216172edc29ee5302eb3477380c7943
4
- data.tar.gz: 98ca1b24cd5bdaa79409de8bf36e10bc573bc6c0b80bf8194bb08eeddc91cf0a
3
+ metadata.gz: d085f703fae0e0d968fe62788d74409d67b487025c76eca89589ded2b985794f
4
+ data.tar.gz: 3f9a0a0e029cb375f970eb2acfea662aced22501302758eedd5c7938ae6ebe26
5
5
  SHA512:
6
- metadata.gz: 13a52d97a5ac5c309a3249dcbd1f5cb15392edc40c87a65a34064be54dfc44e5d6dd5ed6bff63fd4793f6e85297dbff92660fdc50a490d994c4af41e4ed9159c
7
- data.tar.gz: cb8ce77af551b2c015c06ab75114517fe05376c26f1d8b228dde017b25da3685d7d8ee551bc140b50dc15fe06982618d485aab43dc88e7f63ebd47bdbd04769c
6
+ metadata.gz: fac13f5e528c452d3a69f305cfef78e34374f58913125a2ac9291656427ff8895ff303baa29c4244150b1e69dadf8bbadc13520bb02297de34c8e38801da35bc
7
+ data.tar.gz: 2c2f9ee717d50aef99d135c1316e7c3947617592246122461888b2bbb111c3f3204f9677fbef3cf8f33c1e5d04cecb1a4fecbfa99aaa44a772138e79b1663257
@@ -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, {}, creds)
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
- # Turn a gRPC status code into a human-readable string. e.g. 3 -> "InvalidArgument"
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: error_details.upstream_cause)
48
+ cause: upstream_cause)
55
49
  end
56
50
  end
57
51
  end
58
52
 
59
- new(error.message, code: GRPC::Codes::StatusCodes::Unknown, stately_code: "Unknown", cause: error)
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 StatelyDB::Error.from(e)
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 key paths of the items
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(&:value)
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
- if byte_string.encoding == Encoding::BINARY && byte_string.bytesize == 16
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.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-08-28 00:00:00.000000000 Z
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