activemodel-datastore 0.9.0 → 0.10.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 +5 -0
- data/README.md +9 -0
- data/lib/active_model/datastore/version.rb +1 -1
- data/lib/active_model/datastore.rb +39 -27
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 62ccc081e2437c2c1ca324b12a78f888cb14bf5fb0d6cabe8ebee0c1089f3807
|
|
4
|
+
data.tar.gz: 5def43f01da73999c34f0f2a6bc66ead4249eda5df08281dd552da42856b0fea
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 03f469254125d0dc7184395103cdea93648f0551e5a1289721ec5fe2dc382d0ccdf906087734875cfc8e79c815f51be766ab917d76cb2fdd9cde69e5858e1308
|
|
7
|
+
data.tar.gz: 71473fab63f1e02a4472db2a3c828492d1a23fddde05ca45aa275e9037a63cf252dc53140e93ac9bf5bc354a5fa38d549fec5d2c64565cb9f7fc0e7bfd05c896
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
### 0.10.0 / 2026-09-22
|
|
2
|
+
* stop retrying invalid argument errors
|
|
3
|
+
* make read retry counts configurable independently of writes
|
|
4
|
+
* log a warning when a retry chain gives up, including its attempt count
|
|
5
|
+
|
|
1
6
|
### 0.9.0 / 2026-08-24
|
|
2
7
|
* identify the Datastore operation, entity kind, and failed-attempt elapsed time in retry logs
|
|
3
8
|
* use a configurable retry logger that defaults to Rails.logger and falls back to standard output
|
data/README.md
CHANGED
|
@@ -89,6 +89,15 @@ configure it during application initialization:
|
|
|
89
89
|
ActiveModel::Datastore.logger = MyApplication.logger
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
+
To change the gem's read retry count (default: `5`), configure it during initialization:
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
ActiveModel::Datastore.read_retry_count = 2
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Set it to `0` to disable read retries. Write retry counts are unchanged. Invalid argument errors
|
|
99
|
+
are never retried.
|
|
100
|
+
|
|
92
101
|
There is an example Puma config file [here](https://github.com/Agrimatics/activemodel-datastore/blob/main/test/support/datastore_example_rails_app/config/puma.rb).
|
|
93
102
|
|
|
94
103
|
## <a name="model"></a>Model Example
|
|
@@ -127,8 +127,17 @@ module ActiveModel::Datastore
|
|
|
127
127
|
@logger = logger
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
+
def self.read_retry_count
|
|
131
|
+
@read_retry_count || 5
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def self.read_retry_count=(count)
|
|
135
|
+
@read_retry_count = count
|
|
136
|
+
end
|
|
137
|
+
|
|
130
138
|
included do
|
|
131
|
-
private_class_method :query_options, :query_sort, :query_property_filter, :find_all_entities
|
|
139
|
+
private_class_method :query_options, :query_sort, :query_property_filter, :find_all_entities,
|
|
140
|
+
:retry_read, :log_retry_failure
|
|
132
141
|
define_model_callbacks :save, :update, :destroy
|
|
133
142
|
attr_accessor :id, :parent_key_id, :entity_property_values
|
|
134
143
|
end
|
|
@@ -239,7 +248,7 @@ module ActiveModel::Datastore
|
|
|
239
248
|
def find_entity(id_or_name, parent = nil)
|
|
240
249
|
key = CloudDatastore.dataset.key name, id_or_name
|
|
241
250
|
key.parent = parent if parent.present?
|
|
242
|
-
|
|
251
|
+
retry_read('find') { CloudDatastore.dataset.find key }
|
|
243
252
|
end
|
|
244
253
|
|
|
245
254
|
##
|
|
@@ -300,9 +309,7 @@ module ActiveModel::Datastore
|
|
|
300
309
|
def all(options = {})
|
|
301
310
|
next_cursor = nil
|
|
302
311
|
query = build_query(options)
|
|
303
|
-
query_results =
|
|
304
|
-
CloudDatastore.dataset.run query
|
|
305
|
-
end
|
|
312
|
+
query_results = retry_read('run query') { CloudDatastore.dataset.run query }
|
|
306
313
|
if options[:limit]
|
|
307
314
|
next_cursor = query_results.cursor if query_results.size == options[:limit]
|
|
308
315
|
return from_entities(query_results.all), next_cursor
|
|
@@ -354,9 +361,7 @@ module ActiveModel::Datastore
|
|
|
354
361
|
query.ancestor(args[:ancestor]) if args[:ancestor]
|
|
355
362
|
query.limit(1)
|
|
356
363
|
query.where(args.keys[0].to_s, '=', args.values[0])
|
|
357
|
-
query_results =
|
|
358
|
-
CloudDatastore.dataset.run query
|
|
359
|
-
end
|
|
364
|
+
query_results = retry_read('run query') { CloudDatastore.dataset.run query }
|
|
360
365
|
from_entity(query_results.first)
|
|
361
366
|
end
|
|
362
367
|
|
|
@@ -421,16 +426,12 @@ module ActiveModel::Datastore
|
|
|
421
426
|
started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) if operation
|
|
422
427
|
yield
|
|
423
428
|
rescue Google::Cloud::Error => e
|
|
424
|
-
|
|
429
|
+
giving_up = e.is_a?(Google::Cloud::InvalidArgumentError) || retries >= max_retry_count
|
|
430
|
+
ending = "retrying in #{sleep_time}#{' s' if operation}"
|
|
431
|
+
ending = "giving up after #{retries + 1} attempts" if giving_up
|
|
432
|
+
log_retry_failure(e, ending, operation: operation, kind: kind, started_at: started_at)
|
|
433
|
+
return false if giving_up
|
|
425
434
|
|
|
426
|
-
if operation
|
|
427
|
-
elapsed_ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at) * 1000).round
|
|
428
|
-
message = "\e[33mDatastore #{operation} failed for #{kind} after #{elapsed_ms} ms: " \
|
|
429
|
-
"#{e.message.inspect}; retrying in #{sleep_time} s\e[0m"
|
|
430
|
-
else
|
|
431
|
-
message = "\e[33mRescued exception #{e.message.inspect}, retrying in #{sleep_time}\e[0m"
|
|
432
|
-
end
|
|
433
|
-
ActiveModel::Datastore.logger ? ActiveModel::Datastore.logger.warn(message) : puts(message)
|
|
434
435
|
# 0.25, 0.5, 1, 2, and 4 second between retries.
|
|
435
436
|
sleep sleep_time
|
|
436
437
|
retries += 1
|
|
@@ -446,16 +447,12 @@ module ActiveModel::Datastore
|
|
|
446
447
|
started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) if operation
|
|
447
448
|
yield
|
|
448
449
|
rescue Google::Cloud::Error => e
|
|
449
|
-
|
|
450
|
+
giving_up = e.is_a?(Google::Cloud::InvalidArgumentError) || retries >= max_retry_count
|
|
451
|
+
ending = "retrying in #{sleep_time}#{' s' if operation}"
|
|
452
|
+
ending = "giving up after #{retries + 1} attempts" if giving_up
|
|
453
|
+
log_retry_failure(e, ending, operation: operation, kind: kind, started_at: started_at)
|
|
454
|
+
raise if giving_up
|
|
450
455
|
|
|
451
|
-
if operation
|
|
452
|
-
elapsed_ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at) * 1000).round
|
|
453
|
-
message = "\e[33mDatastore #{operation} failed for #{kind} after #{elapsed_ms} ms: " \
|
|
454
|
-
"#{e.message.inspect}; retrying in #{sleep_time} s\e[0m"
|
|
455
|
-
else
|
|
456
|
-
message = "\e[33mRescued exception #{e.message.inspect}, retrying in #{sleep_time}\e[0m"
|
|
457
|
-
end
|
|
458
|
-
ActiveModel::Datastore.logger ? ActiveModel::Datastore.logger.warn(message) : puts(message)
|
|
459
456
|
# 0.25, 0.5, 1, 2, and 4 second between retries.
|
|
460
457
|
sleep sleep_time
|
|
461
458
|
retries += 1
|
|
@@ -473,6 +470,21 @@ module ActiveModel::Datastore
|
|
|
473
470
|
|
|
474
471
|
# **************** private ****************
|
|
475
472
|
|
|
473
|
+
def log_retry_failure(error, ending, operation:, kind:, started_at:)
|
|
474
|
+
if operation
|
|
475
|
+
elapsed_ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at) * 1000).round
|
|
476
|
+
message = "\e[33mDatastore #{operation} failed for #{kind} after #{elapsed_ms} ms: " \
|
|
477
|
+
"#{error.message.inspect}; #{ending}\e[0m"
|
|
478
|
+
else
|
|
479
|
+
message = "\e[33mRescued exception #{error.message.inspect}, #{ending}\e[0m"
|
|
480
|
+
end
|
|
481
|
+
ActiveModel::Datastore.logger ? ActiveModel::Datastore.logger.warn(message) : puts(message)
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
def retry_read(operation, &block)
|
|
485
|
+
retry_on_exception(ActiveModel::Datastore.read_retry_count, operation: operation, &block)
|
|
486
|
+
end
|
|
487
|
+
|
|
476
488
|
def query_options(query, options)
|
|
477
489
|
query.ancestor(options[:ancestor]) if options[:ancestor]
|
|
478
490
|
query.cursor(options[:cursor]) if options[:cursor]
|
|
@@ -521,7 +533,7 @@ module ActiveModel::Datastore
|
|
|
521
533
|
def find_all_entities(ids_or_names, parent)
|
|
522
534
|
keys = ids_or_names.map { |id| CloudDatastore.dataset.key name, id }
|
|
523
535
|
keys.map { |key| key.parent = parent } if parent.present?
|
|
524
|
-
|
|
536
|
+
retry_read('find all') { CloudDatastore.dataset.find_all keys }
|
|
525
537
|
end
|
|
526
538
|
|
|
527
539
|
def build_model(entity)
|