statelydb 0.1.1 → 0.1.3

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
  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