identity_cache 1.6.2 → 1.6.4

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: 463112ddb217364a26a8232ef1958c45bdb24fc7dcd891be3e7d4db4ca4d29a4
4
- data.tar.gz: 13ea742aca4c33f710a6f8a229f6cf0531dba50291c1ec7c67bce735028ce527
3
+ metadata.gz: c1c4e1e77b3c4a778ba9a9b20540aa092a747ab19534cf6b49566bf74f02e5b7
4
+ data.tar.gz: 906ac8772c48e590b2dbacb2507319f04a97af51309fa01822461715ec503212
5
5
  SHA512:
6
- metadata.gz: d4c3cae9c3c4a6444f62d84242326da8901e0aa66895c8b6d2916930a5824fe402299d5e7c6270982e37fa9cd97991310756320aea0fb93b64a1f515a27f1c1f
7
- data.tar.gz: 5512f9b845a4bc9ea8821d6e8563bc4307ba46a32fe32f1f5d2a708b624be3a5ed72c1b64fe2a9ade21f52ffa8d6c3220e23bc3bb433249bceb4d6eacdf7ba67
6
+ metadata.gz: 1a86b5918fbfa174f8d2d01626de61b7b3cfdef06690f0e4c0440be0e5615a74fd84cab6d7e6c7982dcbdc8811e76db3b7f6344f8e2a15dfad3ade11e2cf7e40
7
+ data.tar.gz: 31910c9568c5ead4d8157092933e31d76544e12dfdec5f74c6ac6f24ff9ca41d8bd1587e31e1fee63c0044fadb8ebac104e8854c4d36ceef5dc40b975c4e0f76
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: github-actions
4
+ directory: "/"
5
+ schedule:
6
+ interval: weekly
@@ -19,11 +19,11 @@ jobs:
19
19
  ruby: '3.0'
20
20
  gemfile: "Gemfile.min-supported"
21
21
  - name: 'Latest released & run rubocop'
22
- ruby: '3.3'
22
+ ruby: '3.4'
23
23
  gemfile: "Gemfile.latest-release"
24
24
  rubocop: true
25
25
  - name: 'Rails edge'
26
- ruby: '3.3'
26
+ ruby: '3.4'
27
27
  gemfile: "Gemfile.rails-edge"
28
28
  edge: true
29
29
 
@@ -70,9 +70,9 @@ jobs:
70
70
  sudo apt-get update
71
71
  sudo apt-get -y install libmemcached-dev libmysqlclient-dev libpq-dev libsasl2-dev
72
72
 
73
- - uses: actions/checkout@v2
73
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
74
74
  - name: Set up Ruby
75
- uses: ruby/setup-ruby@v1
75
+ uses: ruby/setup-ruby@4ff6f3611a42bc75eee1e5138240eb1613f48c8f # v1.266.0
76
76
  with:
77
77
  ruby-version: ${{ matrix.entry.ruby }}
78
78
  bundler-cache: true
data/.gitignore CHANGED
@@ -16,3 +16,4 @@ test/version_tmp
16
16
  tmp
17
17
  .rubocop-http*
18
18
  .byebug_history
19
+ gemfiles/*.lock
data/CHANGELOG.md CHANGED
@@ -2,9 +2,17 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 1.6.4
6
+
7
+ - Patch `run_callbacks` instead of `_run_commit_callbacks` to expire cache prior to `after_commit` callbacks. (#602)
8
+
9
+ ## 1.6.3
10
+
11
+ - Split the `with_deferred_parent_expiration` and `with_deferred_parent_expiration`. (#578)
12
+
5
13
  ## 1.6.2
6
14
 
7
- - Support deferred expiry of associations and attributes. Add a rake task to create test database.
15
+ - Support deferred expiry of associations and attributes. Add a rake task to create test database. (#577)
8
16
 
9
17
  ## 1.6.1
10
18
 
data/Gemfile.lock CHANGED
@@ -1,6 +1,6 @@
1
1
  GIT
2
2
  remote: https://github.com/Shopify/memcached.git
3
- revision: 54a89bae698896a00fd2ceeb142dada6285f73ed
3
+ revision: 30f5735d5db2dfd50dd885ceeb51672320b356d3
4
4
  branch: 1-0-stable-shopify
5
5
  specs:
6
6
  memcached (1.9.0)
@@ -8,21 +8,22 @@ GIT
8
8
  PATH
9
9
  remote: .
10
10
  specs:
11
- identity_cache (1.6.2)
11
+ identity_cache (1.6.4)
12
12
  activerecord (>= 7.0)
13
13
  ar_transaction_changes (~> 1.1)
14
14
 
15
15
  GEM
16
16
  remote: https://rubygems.org/
17
17
  specs:
18
- activemodel (7.2.0)
19
- activesupport (= 7.2.0)
20
- activerecord (7.2.0)
21
- activemodel (= 7.2.0)
22
- activesupport (= 7.2.0)
18
+ activemodel (8.0.2)
19
+ activesupport (= 8.0.2)
20
+ activerecord (8.0.2)
21
+ activemodel (= 8.0.2)
22
+ activesupport (= 8.0.2)
23
23
  timeout (>= 0.4.0)
24
- activesupport (7.2.0)
24
+ activesupport (8.0.2)
25
25
  base64
26
+ benchmark (>= 0.3)
26
27
  bigdecimal
27
28
  concurrent-ruby (~> 1.0, >= 1.3.1)
28
29
  connection_pool (>= 2.2.5)
@@ -32,40 +33,42 @@ GEM
32
33
  minitest (>= 5.1)
33
34
  securerandom (>= 0.3)
34
35
  tzinfo (~> 2.0, >= 2.0.5)
36
+ uri (>= 0.13.1)
35
37
  ar_transaction_changes (1.1.9)
36
38
  activerecord (>= 5.2.0)
37
- ast (2.4.2)
38
- base64 (0.2.0)
39
- bigdecimal (3.1.8)
40
- byebug (11.1.3)
39
+ ast (2.4.3)
40
+ base64 (0.3.0)
41
+ benchmark (0.4.1)
42
+ bigdecimal (3.2.2)
43
+ byebug (12.0.0)
41
44
  cityhash (0.6.0)
42
- concurrent-ruby (1.3.4)
43
- connection_pool (2.4.1)
44
- dalli (3.2.3)
45
- drb (2.2.1)
46
- i18n (1.14.5)
45
+ concurrent-ruby (1.3.5)
46
+ connection_pool (2.5.3)
47
+ dalli (3.2.8)
48
+ drb (2.2.3)
49
+ i18n (1.14.7)
47
50
  concurrent-ruby (~> 1.0)
48
- json (2.7.1)
49
- language_server-protocol (3.17.0.3)
50
- logger (1.6.0)
51
+ json (2.13.1)
52
+ language_server-protocol (3.17.0.5)
53
+ logger (1.7.0)
51
54
  memcached_store (2.3.4)
52
55
  activesupport (>= 6)
53
56
  memcached (~> 1.8)
54
- minitest (5.25.1)
55
- mocha (2.1.0)
57
+ minitest (5.25.5)
58
+ mocha (2.7.1)
56
59
  ruby2_keywords (>= 0.0.5)
57
60
  mysql2 (0.5.6)
58
- parallel (1.24.0)
59
- parser (3.3.0.5)
61
+ parallel (1.27.0)
62
+ parser (3.3.9.0)
60
63
  ast (~> 2.4.1)
61
64
  racc
62
- pg (1.5.6)
63
- racc (1.7.3)
65
+ pg (1.5.9)
66
+ prism (1.4.0)
67
+ racc (1.8.1)
64
68
  rainbow (3.1.1)
65
- rake (13.1.0)
66
- regexp_parser (2.9.0)
67
- rexml (3.3.6)
68
- strscan
69
+ rake (13.3.0)
70
+ regexp_parser (2.10.0)
71
+ rexml (3.4.2)
69
72
  rubocop (1.61.0)
70
73
  json (~> 2.3)
71
74
  language_server-protocol (>= 3.17.0)
@@ -77,20 +80,21 @@ GEM
77
80
  rubocop-ast (>= 1.30.0, < 2.0)
78
81
  ruby-progressbar (~> 1.7)
79
82
  unicode-display_width (>= 2.4.0, < 3.0)
80
- rubocop-ast (1.31.2)
81
- parser (>= 3.3.0.4)
83
+ rubocop-ast (1.46.0)
84
+ parser (>= 3.3.7.2)
85
+ prism (~> 1.4)
82
86
  rubocop-shopify (2.9.0)
83
87
  rubocop (~> 1.33)
84
88
  ruby-progressbar (1.13.0)
85
89
  ruby2_keywords (0.0.5)
86
- securerandom (0.3.1)
90
+ securerandom (0.4.1)
87
91
  spy (1.0.5)
88
- stackprof (0.2.26)
89
- strscan (3.1.0)
90
- timeout (0.4.1)
92
+ stackprof (0.2.27)
93
+ timeout (0.4.3)
91
94
  tzinfo (2.0.6)
92
95
  concurrent-ruby (~> 1.0)
93
- unicode-display_width (2.5.0)
96
+ unicode-display_width (2.6.0)
97
+ uri (1.0.3)
94
98
 
95
99
  PLATFORMS
96
100
  arm64-darwin-22
data/Rakefile CHANGED
@@ -9,14 +9,82 @@ require "rdoc/task"
9
9
  desc("Default: run tests and style checks.")
10
10
  task(default: [:test, :rubocop])
11
11
 
12
- desc("Test the identity_cache plugin.")
13
- Rake::TestTask.new(:test) do |t|
14
- t.libs << "lib"
15
- t.libs << "test"
16
- t.pattern = "test/**/*_test.rb"
17
- t.verbose = true
12
+ namespace :test do
13
+ desc "Test the identity_cache plugin with default Gemfile"
14
+ Rake::TestTask.new(:default) do |t|
15
+ t.libs << "lib"
16
+ t.libs << "test"
17
+ t.pattern = "test/**/*_test.rb"
18
+ t.verbose = true
19
+ end
20
+
21
+ desc "Test the identity_cache plugin with minimum supported dependencies"
22
+ task :min_supported do
23
+ gemfile = File.expand_path("gemfiles/Gemfile.min-supported", __dir__)
24
+ ENV["BUNDLE_GEMFILE"] = gemfile
25
+
26
+ puts "\nInstalling dependencies for #{gemfile}..."
27
+ Bundler.with_unbundled_env do
28
+ system("bundle install --gemfile #{gemfile}") || abort("Bundle install failed")
29
+ end
30
+
31
+ puts "Running tests with #{gemfile}..."
32
+ Rake::TestTask.new(:run_min_supported) do |t|
33
+ t.libs << "lib"
34
+ t.libs << "test"
35
+ t.pattern = "test/**/*_test.rb"
36
+ t.verbose = true
37
+ end
38
+ Rake::Task["run_min_supported"].invoke
39
+ end
40
+
41
+ desc "Test the identity_cache plugin with latest released dependencies"
42
+ task :latest_release do
43
+ gemfile = File.expand_path("gemfiles/Gemfile.latest-release", __dir__)
44
+ ENV["BUNDLE_GEMFILE"] = gemfile
45
+
46
+ puts "\nInstalling dependencies for #{gemfile}..."
47
+ Bundler.with_unbundled_env do
48
+ system("bundle install --gemfile #{gemfile}") || abort("Bundle install failed")
49
+ end
50
+
51
+ puts "Running tests with #{gemfile}..."
52
+ Rake::TestTask.new(:run_latest_release) do |t|
53
+ t.libs << "lib"
54
+ t.libs << "test"
55
+ t.pattern = "test/**/*_test.rb"
56
+ t.verbose = true
57
+ end
58
+ Rake::Task["run_latest_release"].invoke
59
+ end
60
+
61
+ desc "Test the identity_cache plugin with rails edge dependencies"
62
+ task :rails_edge do
63
+ gemfile = File.expand_path("gemfiles/Gemfile.rails-edge", __dir__)
64
+ ENV["BUNDLE_GEMFILE"] = gemfile
65
+
66
+ puts "\nInstalling dependencies for #{gemfile}..."
67
+ Bundler.with_unbundled_env do
68
+ system("bundle install --gemfile #{gemfile}") || abort("Bundle install failed")
69
+ end
70
+
71
+ puts "Running tests with #{gemfile}..."
72
+ Rake::TestTask.new(:run_rails_edge) do |t|
73
+ t.libs << "lib"
74
+ t.libs << "test"
75
+ t.pattern = "test/**/*_test.rb"
76
+ t.verbose = true
77
+ end
78
+ Rake::Task["run_rails_edge"].invoke
79
+ end
18
80
  end
19
81
 
82
+ desc "Run default tests"
83
+ task test: ["test:default"]
84
+
85
+ desc "Run all tests (default, min_supported, latest_release, rails_edge)"
86
+ task test_all: ["test:default", "test:min_supported", "test:latest_release", "test:rails_edge"]
87
+
20
88
  task :rubocop do
21
89
  require "rubocop/rake_task"
22
90
  RuboCop::RakeTask.new
data/dev.yml CHANGED
@@ -24,6 +24,10 @@ commands:
24
24
  bundle exec ruby -I test "$@"
25
25
  fi
26
26
 
27
+ test-all:
28
+ desc: "Run tests for all gemfiles (default, min_supported, latest_release, rails_edge)"
29
+ run: bundle exec rake test_all
30
+
27
31
  style:
28
32
  desc: "Run rubocop checks"
29
33
  run: bundle exec rubocop "$@"
@@ -26,7 +26,6 @@ Gem::Specification.new do |gem|
26
26
  gem.files = Dir.chdir(File.expand_path(__dir__)) do
27
27
  %x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^test/}) }
28
28
  end
29
- gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
30
29
  gem.name = "identity_cache"
31
30
  gem.require_paths = ["lib"]
32
31
  gem.version = IdentityCache::VERSION
@@ -47,6 +47,10 @@ module IdentityCache
47
47
  add_parents_to_cache_expiry_set(parents_to_expire)
48
48
  parents_to_expire.select! { |parent| parent.class.primary_cache_index_enabled }
49
49
  parents_to_expire.reduce(true) do |all_expired, parent|
50
+ if Thread.current[:idc_deferred_parent_expiration]
51
+ Thread.current[:idc_parent_records_for_cache_expiry] << parent
52
+ next parent
53
+ end
50
54
  parent.expire_primary_index && all_expired
51
55
  end
52
56
  end
@@ -165,11 +165,20 @@ module IdentityCache
165
165
  # cache reads that happen from the ordering of callbacks. For example, if an after_commit
166
166
  # callback enqueues a background job, then we don't want it to be possible for the
167
167
  # background job to run and load data from the cache before it is invalidated.
168
- def _run_commit_callbacks
169
- if destroyed? || transaction_changed_attributes.present?
170
- expire_cache
168
+ if ActiveRecord.version >= Gem::Version.new("7.1")
169
+ def run_callbacks(kind, type = nil)
170
+ if kind == :commit && (destroyed? || transaction_changed_attributes.present?)
171
+ expire_cache
172
+ end
173
+ super
174
+ end
175
+ else
176
+ def run_callbacks(kind)
177
+ if kind == :commit && (destroyed? || transaction_changed_attributes.present?)
178
+ expire_cache
179
+ end
180
+ super
171
181
  end
172
- super
173
182
  end
174
183
 
175
184
  # Invalidate the cache data associated with the record. Returns `true` on success,
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module IdentityCache
4
- VERSION = "1.6.2"
4
+ VERSION = "1.6.4"
5
5
  CACHE_VERSION = 8
6
6
  end
@@ -60,6 +60,8 @@ module IdentityCache
60
60
 
61
61
  class InverseAssociationError < StandardError; end
62
62
 
63
+ class NestedDeferredParentBlockError < StandardError; end
64
+
63
65
  class NestedDeferredCacheExpirationBlockError < StandardError; end
64
66
 
65
67
  class UnsupportedScopeError < StandardError; end
@@ -202,6 +204,48 @@ module IdentityCache
202
204
  result
203
205
  end
204
206
 
207
+ # Executes a block with deferred parent expiration, ensuring that the parent
208
+ # records' cache expiration is deferred until the block completes. When the block
209
+ # completes, it triggers expiration of the primary index for the parent records.
210
+ # Raises a NestedDeferredParentBlockError if a deferred parent expiration block
211
+ # is already active on the current thread.
212
+ #
213
+ # == Parameters:
214
+ # No parameters.
215
+ #
216
+ # == Raises:
217
+ # NestedDeferredParentBlockError if a deferred parent expiration block is already active.
218
+ #
219
+ # == Yield:
220
+ # Runs the provided block with deferred parent expiration.
221
+ #
222
+ # == Returns:
223
+ # The result of executing the provided block.
224
+ #
225
+ # == Ensures:
226
+ # Cleans up thread-local variables related to deferred parent expiration regardless
227
+ # of whether the block raises an exception.
228
+ def with_deferred_parent_expiration
229
+ raise NestedDeferredParentBlockError if Thread.current[:idc_deferred_parent_expiration]
230
+
231
+ if Thread.current[:idc_deferred_expiration]
232
+ deprecator.deprecation_warning("`with_deferred_parent_expiration`")
233
+ end
234
+
235
+ Thread.current[:idc_deferred_parent_expiration] = true
236
+ Thread.current[:idc_parent_records_for_cache_expiry] = Set.new
237
+
238
+ result = yield
239
+
240
+ Thread.current[:idc_deferred_parent_expiration] = nil
241
+ Thread.current[:idc_parent_records_for_cache_expiry].each(&:expire_primary_index)
242
+
243
+ result
244
+ ensure
245
+ Thread.current[:idc_deferred_parent_expiration] = nil
246
+ Thread.current[:idc_parent_records_for_cache_expiry]&.clear
247
+ end
248
+
205
249
  # Executes a block with deferred cache expiration, ensuring that the records' (parent,
206
250
  # children and attributes) cache expiration is deferred until the block completes. When
207
251
  # the block completes, it issues delete_multi calls for all the records and attributes
@@ -225,6 +269,10 @@ module IdentityCache
225
269
  def with_deferred_expiration
226
270
  raise NestedDeferredCacheExpirationBlockError if Thread.current[:idc_deferred_expiration]
227
271
 
272
+ if Thread.current[:idc_deferred_parent_expiration]
273
+ deprecator.deprecation_warning("`with_deferred_parent_expiration`")
274
+ end
275
+
228
276
  Thread.current[:idc_deferred_expiration] = true
229
277
  Thread.current[:idc_records_to_expire] = Set.new
230
278
  Thread.current[:idc_attributes_to_expire] = Set.new
@@ -268,6 +316,10 @@ module IdentityCache
268
316
  ParentModelExpiration.install_all_pending_parent_expiry_hooks
269
317
  end
270
318
 
319
+ def deprecator
320
+ @deprecator ||= ActiveSupport::Deprecation.new("1.7.0", "IdentityCache")
321
+ end
322
+
271
323
  private
272
324
 
273
325
  def fetch_in_batches(keys, &block)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: identity_cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.2
4
+ version: 1.6.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Camilo Lopez
@@ -11,10 +11,9 @@ authors:
11
11
  - Tobias Lutke
12
12
  - Arthur Neves
13
13
  - Francis Bogsanyi
14
- autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
- date: 2024-10-10 00:00:00.000000000 Z
16
+ date: 1980-01-02 00:00:00.000000000 Z
18
17
  dependencies:
19
18
  - !ruby/object:Gem::Dependency
20
19
  name: activerecord
@@ -107,6 +106,7 @@ executables: []
107
106
  extensions: []
108
107
  extra_rdoc_files: []
109
108
  files:
109
+ - ".github/dependabot.yml"
110
110
  - ".github/workflows/ci.yml"
111
111
  - ".github/workflows/cla.yml"
112
112
  - ".gitignore"
@@ -176,7 +176,6 @@ homepage: https://github.com/Shopify/identity_cache
176
176
  licenses: []
177
177
  metadata:
178
178
  allowed_push_host: https://rubygems.org
179
- post_install_message:
180
179
  rdoc_options: []
181
180
  require_paths:
182
181
  - lib
@@ -191,8 +190,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
191
190
  - !ruby/object:Gem::Version
192
191
  version: '0'
193
192
  requirements: []
194
- rubygems_version: 3.5.21
195
- signing_key:
193
+ rubygems_version: 3.7.2
196
194
  specification_version: 4
197
195
  summary: IdentityCache lets you specify how you want to cache your model objects,
198
196
  at the model level, and adds a number of convenience methods for accessing those