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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3126172160a1df49727e648493401c8448f62a1442cba738dcf139d6406dfdce
4
- data.tar.gz: 24bc7d6985f16739f16561611255d23ac6862cd72502f50827462a3c0674e6aa
3
+ metadata.gz: 62ccc081e2437c2c1ca324b12a78f888cb14bf5fb0d6cabe8ebee0c1089f3807
4
+ data.tar.gz: 5def43f01da73999c34f0f2a6bc66ead4249eda5df08281dd552da42856b0fea
5
5
  SHA512:
6
- metadata.gz: bc4e6401b2932e11c37b509dc1f98561423b6908d0d11f0465363090239a67ae6f7dc02cc5aecedc6fb72e4e8168f44a6ddc9fe38d49665fc6fc95838e0144a8
7
- data.tar.gz: 7acf7b5d14306afb3412c7ac667806e05708de0b9a8e8348b172bafa337316f4b11160f68eee3bb1152e27d7fa6ae066d4d28e17f430365b6caf003a3dfdbd1c
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
@@ -1,5 +1,5 @@
1
1
  module ActiveModel
2
2
  module Datastore
3
- VERSION = '0.9.0'
3
+ VERSION = '0.10.0'
4
4
  end
5
5
  end
@@ -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
- retry_on_exception(operation: 'find') { CloudDatastore.dataset.find key }
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 = retry_on_exception(operation: 'run query') do
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 = retry_on_exception(operation: 'run query') do
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
- return false if retries >= max_retry_count
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
- raise e if retries >= max_retry_count
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
- retry_on_exception(operation: 'find all') { CloudDatastore.dataset.find_all keys }
536
+ retry_read('find all') { CloudDatastore.dataset.find_all keys }
525
537
  end
526
538
 
527
539
  def build_model(entity)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activemodel-datastore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bryce McLean