atomic_cache 0.5.1.rc1 → 0.5.2.rc1

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: f03b8f8d9294f3a40ea719ea5165d4c6789c3eebb36459768c8fbd0c57d8fc3a
4
- data.tar.gz: b2a320b8323c57785e0202e29d89922b33e63fc9ebd898d6df61f76fb5e2600c
3
+ metadata.gz: 47216ee7b28e97d5a2a0d45ec7a7831d6ee05038f2029498654006b7ad42171c
4
+ data.tar.gz: 025c598a7d72bd3387c0fe0057a3047227ad9c6ae67ed818912a98d3a3f21e05
5
5
  SHA512:
6
- metadata.gz: f461c2bf7d903c6f7940334b8f5d11672c7ed04d1d55ad5d25c2337c07906d24a39f8958ddf04a2dd5d5dc690c9a0920121fb99c9f25c809c08959e48ee13ae3
7
- data.tar.gz: 9100ad9f5e5012c3729e3bc3a3b95ca64705c562f14e5d610df9f223436ee9351ec58cddc64b61c87c186a588f18e6158e891308aa5d431739f56aa2562744fa
6
+ metadata.gz: d575cb83f4bd7a97d902ad8b15d2da5063ea12edfcadc4d4b6c21f9ea1600413635cb84ee98025747bf49a82a7f97a91a73a5ba6152d7c5095ce19b556c5b7ad
7
+ data.tar.gz: 19486f04dfeb751f70b8e1c828b6affa6619829f2a467b87070b4c81a38d7656a57d7ceb02d935d1cf33e3bf4fc47f1356769cb27a19ae177a73cd0af86dbb6b
@@ -93,8 +93,8 @@ module AtomicCache
93
93
  end
94
94
 
95
95
  new_key = @timestamp_manager.next_key(keyspace, lmt)
96
- @timestamp_manager.promote(keyspace, last_known_key: new_key, timestamp: lmt)
97
96
  @storage.set(new_key, new_value, options)
97
+ @timestamp_manager.promote(keyspace, last_known_key: new_key, timestamp: lmt)
98
98
 
99
99
  metrics(:increment, 'generate.current-thread', tags: tags)
100
100
  log(:debug, "Generating new value for `#{new_key}`")
@@ -144,6 +144,16 @@ module AtomicCache
144
144
  if !value.nil?
145
145
  metrics(:increment, 'wait.present', tags: metrics_tags)
146
146
  return value
147
+ else
148
+ # if we didn't get a fresh value this go-round, check if there's a last known value
149
+ # if expirations were to come in rapidly, it's possible that the expiration which caused
150
+ # the wait cycle wrote a value, and it's now in LKV, and a new expiration came in, which
151
+ # has moved the LMT forward
152
+ value = last_known_value(keyspace, options, tags)
153
+ if !value.nil?
154
+ metrics(:increment, 'wait.lkv.present', tags: metrics_tags)
155
+ return value
156
+ end
147
157
  end
148
158
  end
149
159
 
@@ -44,8 +44,7 @@ module AtomicCache
44
44
  # @param last_known_key [String] a key with a known value to refer other processes to
45
45
  # @param timestamp [String, Numeric, Time] the timestamp with which the last_known_key was updated at
46
46
  def promote(keyspace, last_known_key:, timestamp:)
47
- key = keyspace.last_known_key_key
48
- @storage.set(key, last_known_key)
47
+ @storage.set(keyspace.last_known_key_key, last_known_key)
49
48
  @storage.set(last_modified_time_key, self.format(timestamp))
50
49
  end
51
50
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AtomicCache
4
- VERSION = "0.5.1.rc1"
4
+ VERSION = "0.5.2.rc1"
5
5
  end
@@ -163,6 +163,26 @@ describe 'AtomicCacheClient' do
163
163
  expect(result).to eq(new_value)
164
164
  end
165
165
 
166
+ it 'uses the last known value if the LMT increments while waiting' do
167
+ key_storage.set(timestamp_manager.last_modified_time_key, '1420090000')
168
+ key_storage.set(keyspace.last_known_key_key, 'lkk_key')
169
+ last_known_value = 'value from another thread'
170
+
171
+ # fetching the 'fresh' value continually returns nil (because LMT is incrementing forward)
172
+ allow(cache_storage).to receive(:read)
173
+ .with(timestamp_manager.current_key(keyspace), anything)
174
+ .and_return(nil, nil, nil, nil)
175
+
176
+ # multiple returned values are faking what it would look like if another process
177
+ # promoted a value (wrote LKV) but then the cache expired right after
178
+ allow(cache_storage).to receive(:read)
179
+ .with(timestamp_manager.last_known_key(keyspace), anything)
180
+ .and_return(nil, nil, nil, last_known_value)
181
+
182
+ result = subject.fetch(keyspace, backoff_duration_ms: 5) { 'value from generate' }
183
+ expect(result).to eq(last_known_value)
184
+ end
185
+
166
186
  it 'stops waiting when the max retry count is reached' do
167
187
  timestamp_manager.promote(keyspace, last_known_key: 'asdf', timestamp: 1420090000)
168
188
  result = subject.fetch(keyspace, backoff_duration_ms: 5) { 'value from generate' }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atomic_cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1.rc1
4
+ version: 0.5.2.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ibotta Developers
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-07-12 00:00:00.000000000 Z
12
+ date: 2021-07-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler