rails-brotli-cache 0.6.2 → 0.6.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 +4 -4
- data/.github/workflows/ci.yml +1 -1
- data/Gemfile +1 -1
- data/README.md +3 -3
- data/Rakefile +2 -2
- data/benchmarks/Gemfile +7 -6
- data/benchmarks/main.rb +112 -11
- data/lib/rails-brotli-cache/store.rb +23 -16
- data/lib/rails-brotli-cache/version.rb +1 -1
- data/lib/rails-brotli-cache.rb +1 -2
- data/rails-brotli-cache.gemspec +13 -12
- data/spec/dummy/Gemfile +0 -1
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/environments/production.rb +4 -4
- data/spec/dummy/config/environments/test.rb +2 -2
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +1 -1
- data/spec/rails-brotli-cache/cache_keys_spec.rb +4 -4
- data/spec/rails-brotli-cache/compatibility_spec.rb +5 -6
- data/spec/rails-brotli-cache/rails_store_spec.rb +2 -2
- data/spec/rails-brotli-cache/redis_spec.rb +3 -3
- data/spec/rails-brotli-cache/store_spec.rb +61 -9
- data/spec/spec_helper.rb +15 -16
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: deb7fb5b6df5533b08e76b59062ff0a1897822e74031108ae45efbff9612cc74
|
4
|
+
data.tar.gz: cbfe23f39e63c70e30d3ac1dc412d38ab9a0b725e6da63f6a724423774d6c99b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e28ac7994f28b176b086f80ae3bdd163a72c285a094d0b51bfa55ffee4f75b845414ed6a30487db60a158ad2e66795eae17ccde70a5f06cf4a1f84d0d5e7e3c
|
7
|
+
data.tar.gz: 2490251b4a3f29f0121132b18b127c23c152b07a7e187844fb061aacb76e448342de0cf8f1c5b20ea203371c7da9d6dc3b26fe4332f2f862c2bcf8726f316137
|
data/.github/workflows/ci.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -134,7 +134,7 @@ By default gem uses a Brotli compression, but you can customize the algorithm. Y
|
|
134
134
|
```ruby
|
135
135
|
config.cache_store = RailsBrotliCache::Store.new(
|
136
136
|
ActiveSupport::Cache::RedisCacheStore.new,
|
137
|
-
{ compressor_class:
|
137
|
+
{ compressor_class: ZSTDCompressor }
|
138
138
|
)
|
139
139
|
```
|
140
140
|
|
@@ -142,7 +142,7 @@ config.cache_store = RailsBrotliCache::Store.new(
|
|
142
142
|
|
143
143
|
class ZSTDCompressor
|
144
144
|
def self.deflate(payload)
|
145
|
-
::Zstd.compress(payload, 10)
|
145
|
+
::Zstd.compress(payload, level: 10)
|
146
146
|
end
|
147
147
|
|
148
148
|
def self.inflate(payload)
|
@@ -150,7 +150,7 @@ class ZSTDCompressor
|
|
150
150
|
end
|
151
151
|
end
|
152
152
|
|
153
|
-
Rails.cache.write('test-key', json, compressor_class:
|
153
|
+
Rails.cache.write('test-key', json, compressor_class: ZSTDCompressor)
|
154
154
|
```
|
155
155
|
|
156
156
|
This config expects a class that defines two methods, `inflate` and `deflate`. It allows to use, for example, a [ZSTD by Facebook](https://github.com/SpringMT/zstd-ruby), offering even better performance and compression.
|
data/Rakefile
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
-
require
|
2
|
+
require "rspec/core/rake_task"
|
3
3
|
|
4
4
|
RSpec::Core::RakeTask.new(:spec)
|
5
5
|
|
6
6
|
task default: :spec
|
7
7
|
|
8
|
-
desc
|
8
|
+
desc "Test all cache_stores"
|
9
9
|
task :test_all do
|
10
10
|
system("TEST_RAILS_CACHE_STORE=redis_cache_store bundle exec rspec spec && TEST_RAILS_CACHE_STORE=brotli_cache_store bundle exec rspec spec && TEST_RAILS_CACHE_STORE=mem_cache_store bundle exec rspec spec && bundle exec rspec spec")
|
11
11
|
end
|
data/benchmarks/Gemfile
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
source
|
1
|
+
source "https://rubygems.org"
|
2
2
|
|
3
|
-
gem
|
4
|
-
gem
|
5
|
-
gem
|
6
|
-
gem
|
7
|
-
gem
|
3
|
+
gem "brotli"
|
4
|
+
gem "rails-brotli-cache", path: "../"
|
5
|
+
gem "redis"
|
6
|
+
gem "dalli"
|
7
|
+
gem "zstd-ruby"
|
8
|
+
gem "lz4-ruby"
|
data/benchmarks/main.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
1
|
+
require "active_support"
|
2
|
+
require "active_support/core_ext/hash"
|
3
|
+
require "net/http"
|
4
|
+
require "brotli"
|
5
|
+
require "rails-brotli-cache"
|
6
|
+
require "benchmark"
|
7
|
+
require "zstd-ruby"
|
8
|
+
require "lz4-ruby"
|
8
9
|
|
9
10
|
class ZSTDCompressor
|
10
11
|
def self.deflate(payload)
|
11
|
-
::Zstd.compress(payload, 10)
|
12
|
+
::Zstd.compress(payload, level: 10)
|
12
13
|
end
|
13
14
|
|
14
15
|
def self.inflate(payload)
|
@@ -16,21 +17,49 @@ class ZSTDCompressor
|
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
20
|
+
class LZ4Compressor
|
21
|
+
def self.deflate(payload)
|
22
|
+
::LZ4::compress(payload)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.inflate(payload)
|
26
|
+
::LZ4::uncompress(payload)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class LZ4HCCompressor
|
31
|
+
def self.deflate(payload)
|
32
|
+
::LZ4::compressHC(payload)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.inflate(payload)
|
36
|
+
::LZ4::uncompress(payload)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
19
40
|
memory_cache = ActiveSupport::Cache::MemoryStore.new(compress: true) # memory store does not use compression by default
|
20
41
|
brotli_memory_cache = RailsBrotliCache::Store.new(memory_cache)
|
21
42
|
zstd_memory_cache = RailsBrotliCache::Store.new(memory_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
|
43
|
+
lz4_memory_cache = RailsBrotliCache::Store.new(memory_cache, compressor_class: LZ4Compressor, prefix: "lz4-")
|
44
|
+
lz4hc_memory_cache = RailsBrotliCache::Store.new(memory_cache, compressor_class: LZ4HCCompressor, prefix: "lz4hc-")
|
22
45
|
|
23
46
|
redis_cache = ActiveSupport::Cache::RedisCacheStore.new
|
24
47
|
brotli_redis_cache = RailsBrotliCache::Store.new(redis_cache)
|
25
48
|
zstd_redis_cache = RailsBrotliCache::Store.new(redis_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
|
49
|
+
lz4_redis_cache = RailsBrotliCache::Store.new(redis_cache, compressor_class: LZ4Compressor, prefix: "lz4-")
|
50
|
+
lz4hc_redis_cache = RailsBrotliCache::Store.new(redis_cache, compressor_class: LZ4HCCompressor, prefix: "lz4hc-")
|
26
51
|
|
27
52
|
memcached_cache = ActiveSupport::Cache::MemCacheStore.new
|
28
53
|
brotli_memcached_cache = RailsBrotliCache::Store.new(memcached_cache)
|
29
54
|
zstd_memcached_cache = RailsBrotliCache::Store.new(memcached_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
|
55
|
+
lz4_memcached_cache = RailsBrotliCache::Store.new(memcached_cache, compressor_class: LZ4Compressor, prefix: "lz4-")
|
56
|
+
lz4hc_memcached_cache = RailsBrotliCache::Store.new(memcached_cache, compressor_class: LZ4HCCompressor, prefix: "lz4hc-")
|
30
57
|
|
31
|
-
file_cache = ActiveSupport::Cache::FileStore.new(
|
58
|
+
file_cache = ActiveSupport::Cache::FileStore.new("/tmp")
|
32
59
|
brotli_file_cache = RailsBrotliCache::Store.new(file_cache)
|
33
60
|
zstd_file_cache = RailsBrotliCache::Store.new(file_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
|
61
|
+
lz4_file_cache = RailsBrotliCache::Store.new(file_cache, compressor_class: LZ4Compressor, prefix: "lz4-")
|
62
|
+
lz4hc_file_cache = RailsBrotliCache::Store.new(file_cache, compressor_class: LZ4HCCompressor, prefix: "lz4hc-")
|
34
63
|
|
35
64
|
json_uri = URI("https://raw.githubusercontent.com/pawurb/rails-brotli-cache/main/spec/fixtures/sample.json")
|
36
65
|
json = Net::HTTP.get(json_uri)
|
@@ -46,7 +75,7 @@ br_json_size = redis_cache.redis.with do |conn|
|
|
46
75
|
conn.get("br-json").size
|
47
76
|
end
|
48
77
|
puts "Brotli JSON size: #{br_json_size}"
|
49
|
-
puts "~#{((gzip_json_size - br_json_size).to_f / gzip_json_size.to_f * 100).round}%
|
78
|
+
puts "~#{((gzip_json_size - br_json_size).to_f / gzip_json_size.to_f * 100).round}% difference"
|
50
79
|
puts ""
|
51
80
|
|
52
81
|
zstd_redis_cache.write("json", json)
|
@@ -54,7 +83,23 @@ zs_json_size = redis_cache.redis.with do |conn|
|
|
54
83
|
conn.get("zs-json").size
|
55
84
|
end
|
56
85
|
puts "ZSTD JSON size: #{zs_json_size}"
|
57
|
-
puts "~#{((gzip_json_size - zs_json_size).to_f / gzip_json_size.to_f * 100).round}%
|
86
|
+
puts "~#{((gzip_json_size - zs_json_size).to_f / gzip_json_size.to_f * 100).round}% difference"
|
87
|
+
puts ""
|
88
|
+
|
89
|
+
lz4_redis_cache.write("json", json)
|
90
|
+
lz4_json_size = redis_cache.redis.with do |conn|
|
91
|
+
conn.get("lz4-json").size
|
92
|
+
end
|
93
|
+
puts "LZ4 JSON size: #{lz4_json_size}"
|
94
|
+
puts "~#{((gzip_json_size - lz4_json_size).to_f / gzip_json_size.to_f * 100).round}% difference"
|
95
|
+
puts ""
|
96
|
+
|
97
|
+
lz4hc_redis_cache.write("json", json)
|
98
|
+
lz4hc_json_size = redis_cache.redis.with do |conn|
|
99
|
+
conn.get("lz4hc-json").size
|
100
|
+
end
|
101
|
+
puts "LZ4HC JSON size: #{lz4hc_json_size}"
|
102
|
+
puts "~#{((gzip_json_size - lz4hc_json_size).to_f / gzip_json_size.to_f * 100).round}% difference"
|
58
103
|
puts ""
|
59
104
|
|
60
105
|
iterations = 100
|
@@ -81,6 +126,20 @@ Benchmark.bm do |x|
|
|
81
126
|
end
|
82
127
|
end
|
83
128
|
|
129
|
+
x.report("lz4_memory_cache") do
|
130
|
+
iterations.times do
|
131
|
+
lz4_memory_cache.write("test", json)
|
132
|
+
lz4_memory_cache.read("test")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
x.report("lz4hc_memory_cache") do
|
137
|
+
iterations.times do
|
138
|
+
lz4hc_memory_cache.write("test", json)
|
139
|
+
lz4hc_memory_cache.read("test")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
84
143
|
x.report("redis_cache") do
|
85
144
|
iterations.times do
|
86
145
|
redis_cache.write("test", json)
|
@@ -102,6 +161,20 @@ Benchmark.bm do |x|
|
|
102
161
|
end
|
103
162
|
end
|
104
163
|
|
164
|
+
x.report("lz4_redis_cache") do
|
165
|
+
iterations.times do
|
166
|
+
lz4_redis_cache.write("test", json)
|
167
|
+
lz4_redis_cache.read("test")
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
x.report("lz4hc_redis_cache") do
|
172
|
+
iterations.times do
|
173
|
+
lz4hc_redis_cache.write("test", json)
|
174
|
+
lz4hc_redis_cache.read("test")
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
105
178
|
x.report("memcached_cache") do
|
106
179
|
iterations.times do
|
107
180
|
memcached_cache.write("test", json)
|
@@ -123,6 +196,20 @@ Benchmark.bm do |x|
|
|
123
196
|
end
|
124
197
|
end
|
125
198
|
|
199
|
+
x.report("lz4_memcached_cache") do
|
200
|
+
iterations.times do
|
201
|
+
lz4_memcached_cache.write("test", json)
|
202
|
+
lz4_memcached_cache.read("test")
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
x.report("lz4hc_memcached_cache") do
|
207
|
+
iterations.times do
|
208
|
+
lz4hc_memcached_cache.write("test", json)
|
209
|
+
lz4hc_memcached_cache.read("test")
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
126
213
|
x.report("file_cache") do
|
127
214
|
iterations.times do
|
128
215
|
file_cache.write("test", json)
|
@@ -143,4 +230,18 @@ Benchmark.bm do |x|
|
|
143
230
|
zstd_file_cache.read("test")
|
144
231
|
end
|
145
232
|
end
|
233
|
+
|
234
|
+
x.report("lz4_file_cache") do
|
235
|
+
iterations.times do
|
236
|
+
lz4_file_cache.write("test", json)
|
237
|
+
lz4_file_cache.read("test")
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
x.report("lz4hc_file_cache") do
|
242
|
+
iterations.times do
|
243
|
+
lz4hc_file_cache.write("test", json)
|
244
|
+
lz4hc_file_cache.read("test")
|
245
|
+
end
|
246
|
+
end
|
146
247
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "active_support/cache"
|
4
4
|
begin
|
5
|
-
require
|
5
|
+
require "brotli"
|
6
6
|
rescue LoadError
|
7
7
|
end
|
8
8
|
|
@@ -25,7 +25,7 @@ module RailsBrotliCache
|
|
25
25
|
DEFAULT_OPTIONS = {
|
26
26
|
compress_threshold: COMPRESS_THRESHOLD,
|
27
27
|
compress: true,
|
28
|
-
compressor_class: BrotliCompressor
|
28
|
+
compressor_class: BrotliCompressor,
|
29
29
|
}
|
30
30
|
|
31
31
|
attr_reader :core_store
|
@@ -33,10 +33,10 @@ module RailsBrotliCache
|
|
33
33
|
def initialize(core_store, options = {})
|
34
34
|
@core_store = core_store
|
35
35
|
@prefix = if options.key?(:prefix)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
options.fetch(:prefix)
|
37
|
+
else
|
38
|
+
"br-"
|
39
|
+
end
|
40
40
|
|
41
41
|
@init_options = options.reverse_merge(DEFAULT_OPTIONS)
|
42
42
|
end
|
@@ -87,9 +87,9 @@ module RailsBrotliCache
|
|
87
87
|
new_hash = hash.map do |key, val|
|
88
88
|
[
|
89
89
|
expanded_cache_key(key),
|
90
|
-
compressed(val, options)
|
90
|
+
compressed(val, options),
|
91
91
|
]
|
92
|
-
end
|
92
|
+
end.to_h
|
93
93
|
|
94
94
|
@core_store.write_multi(
|
95
95
|
new_hash,
|
@@ -107,17 +107,24 @@ module RailsBrotliCache
|
|
107
107
|
end.to_h
|
108
108
|
end
|
109
109
|
|
110
|
+
def delete_multi(names, options = nil)
|
111
|
+
options = (options || {}).reverse_merge(@init_options)
|
112
|
+
names = names.map { |name| expanded_cache_key(name) }
|
113
|
+
|
114
|
+
core_store.delete_multi(names, options)
|
115
|
+
end
|
116
|
+
|
110
117
|
def fetch_multi(*names)
|
111
118
|
options = names.extract_options!
|
112
119
|
expanded_names = names.map { |name| expanded_cache_key(name) }
|
113
120
|
options = options.reverse_merge(@init_options)
|
114
121
|
|
115
|
-
reads
|
122
|
+
reads = core_store.send(:read_multi_entries, expanded_names, **options)
|
116
123
|
reads.map do |key, val|
|
117
124
|
[source_cache_key(key), uncompressed(val, options)]
|
118
125
|
end.to_h
|
119
126
|
|
120
|
-
writes
|
127
|
+
writes = {}
|
121
128
|
ordered = names.index_with do |name|
|
122
129
|
reads.fetch(name) { writes[name] = yield(name) }
|
123
130
|
end
|
@@ -175,11 +182,11 @@ module RailsBrotliCache
|
|
175
182
|
return payload if payload.is_a?(Integer)
|
176
183
|
|
177
184
|
serialized = if payload.start_with?(MARK_BR_COMPRESSED)
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
185
|
+
compressor = options.fetch(:compressor_class)
|
186
|
+
compressor.inflate(payload.byteslice(1..-1))
|
187
|
+
else
|
188
|
+
payload
|
189
|
+
end
|
183
190
|
|
184
191
|
Marshal.load(serialized)
|
185
192
|
end
|
data/lib/rails-brotli-cache.rb
CHANGED
data/rails-brotli-cache.gemspec
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require "rails-brotli-cache/version"
|
5
5
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
|
-
gem.name
|
8
|
-
gem.version
|
9
|
-
gem.authors
|
10
|
-
gem.email
|
11
|
-
gem.summary
|
12
|
-
gem.description
|
13
|
-
gem.homepage
|
14
|
-
gem.files
|
15
|
-
gem.test_files
|
7
|
+
gem.name = "rails-brotli-cache"
|
8
|
+
gem.version = RailsBrotliCache::VERSION
|
9
|
+
gem.authors = ["pawurb"]
|
10
|
+
gem.email = ["contact@pawelurbanek.com"]
|
11
|
+
gem.summary = %q{ Drop-in enhancement for Rails cache, offering better performance and compression with Brotli algorithm. }
|
12
|
+
gem.description = %q{ This gem reduces storage needed for Rails cache by using Brotli compression, which can produce outputs smaller by ~20% and offers better performance than Gzip. }
|
13
|
+
gem.homepage = "https://github.com/pawurb/rails-brotli-cache"
|
14
|
+
gem.files = `git ls-files`.split("\n")
|
15
|
+
gem.test_files = gem.files.grep(%r{^(spec)/})
|
16
16
|
gem.require_paths = ["lib"]
|
17
|
-
gem.license
|
17
|
+
gem.license = "MIT"
|
18
18
|
gem.add_dependency "activesupport"
|
19
19
|
gem.add_development_dependency "brotli"
|
20
20
|
gem.add_development_dependency "rspec"
|
@@ -24,6 +24,7 @@ Gem::Specification.new do |gem|
|
|
24
24
|
gem.add_development_dependency "redis"
|
25
25
|
gem.add_development_dependency "dalli"
|
26
26
|
gem.add_development_dependency "byebug"
|
27
|
+
gem.add_development_dependency "rufo"
|
27
28
|
|
28
29
|
if gem.respond_to?(:metadata=)
|
29
30
|
gem.metadata = { "rubygems_mfa_required" => "true" }
|
data/spec/dummy/Gemfile
CHANGED
@@ -22,7 +22,7 @@ module Dummy
|
|
22
22
|
class Application < Rails::Application
|
23
23
|
# Initialize configuration defaults for originally generated Rails version.
|
24
24
|
|
25
|
-
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new(
|
25
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7")
|
26
26
|
config.load_defaults 7.0
|
27
27
|
else
|
28
28
|
config.load_defaults 6.0
|
@@ -13,7 +13,7 @@ Rails.application.configure do
|
|
13
13
|
config.eager_load = true
|
14
14
|
|
15
15
|
# Full error reports are disabled and caching is turned on.
|
16
|
-
config.consider_all_requests_local
|
16
|
+
config.consider_all_requests_local = false
|
17
17
|
config.action_controller.perform_caching = true
|
18
18
|
|
19
19
|
# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
|
@@ -45,7 +45,7 @@ Rails.application.configure do
|
|
45
45
|
config.log_level = :info
|
46
46
|
|
47
47
|
# Prepend all log lines with the following tags.
|
48
|
-
config.log_tags = [
|
48
|
+
config.log_tags = [:request_id]
|
49
49
|
|
50
50
|
# Use a different cache store in production.
|
51
51
|
# config.cache_store = :mem_cache_store
|
@@ -65,8 +65,8 @@ Rails.application.configure do
|
|
65
65
|
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name")
|
66
66
|
|
67
67
|
if ENV["RAILS_LOG_TO_STDOUT"].present?
|
68
|
-
logger
|
68
|
+
logger = ActiveSupport::Logger.new(STDOUT)
|
69
69
|
logger.formatter = config.log_formatter
|
70
|
-
config.logger
|
70
|
+
config.logger = ActiveSupport::TaggedLogging.new(logger)
|
71
71
|
end
|
72
72
|
end
|
@@ -19,11 +19,11 @@ Rails.application.configure do
|
|
19
19
|
# Configure public file server for tests with Cache-Control for performance.
|
20
20
|
config.public_file_server.enabled = true
|
21
21
|
config.public_file_server.headers = {
|
22
|
-
"Cache-Control" => "public, max-age=#{1.hour.to_i}"
|
22
|
+
"Cache-Control" => "public, max-age=#{1.hour.to_i}",
|
23
23
|
}
|
24
24
|
|
25
25
|
# Show full error reports and disable caching.
|
26
|
-
config.consider_all_requests_local
|
26
|
+
config.consider_all_requests_local = true
|
27
27
|
config.action_controller.perform_caching = false
|
28
28
|
config.cache_store = :null_store
|
29
29
|
|
@@ -4,5 +4,5 @@
|
|
4
4
|
# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported
|
5
5
|
# notations and behaviors.
|
6
6
|
Rails.application.config.filter_parameters += [
|
7
|
-
:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
|
7
|
+
:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn,
|
8
8
|
]
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spec_helper"
|
4
4
|
|
5
|
-
return unless ENV[
|
5
|
+
return unless ENV["TEST_RAILS_CACHE_STORE"] == "redis_cache_store"
|
6
6
|
|
7
7
|
describe RailsBrotliCache do
|
8
8
|
class Post
|
@@ -60,7 +60,7 @@ describe RailsBrotliCache do
|
|
60
60
|
context "custom namespace string is not duplicated" do
|
61
61
|
let(:options) do
|
62
62
|
{
|
63
|
-
namespace: "myapp"
|
63
|
+
namespace: "myapp",
|
64
64
|
}
|
65
65
|
end
|
66
66
|
|
@@ -77,7 +77,7 @@ describe RailsBrotliCache do
|
|
77
77
|
context "custom namespace proc" do
|
78
78
|
let(:options) do
|
79
79
|
{
|
80
|
-
namespace: -> { "myapp" }
|
80
|
+
namespace: -> { "myapp" },
|
81
81
|
}
|
82
82
|
end
|
83
83
|
|
@@ -1,15 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spec_helper"
|
4
4
|
|
5
5
|
describe RailsBrotliCache do
|
6
|
-
|
7
6
|
CACHE_STORE_TYPES = [
|
8
7
|
[ActiveSupport::Cache::MemoryStore.new, ActiveSupport::Cache::MemoryStore.new],
|
9
8
|
[ActiveSupport::Cache::RedisCacheStore.new, ActiveSupport::Cache::RedisCacheStore.new],
|
10
9
|
[ActiveSupport::Cache::MemCacheStore.new, ActiveSupport::Cache::MemCacheStore.new],
|
11
|
-
[ActiveSupport::Cache::FileStore.new(
|
12
|
-
[ActiveSupport::Cache::NullStore.new, ActiveSupport::Cache::NullStore.new]
|
10
|
+
[ActiveSupport::Cache::FileStore.new("./tmp"), ActiveSupport::Cache::FileStore.new("./tmp")],
|
11
|
+
[ActiveSupport::Cache::NullStore.new, ActiveSupport::Cache::NullStore.new],
|
13
12
|
]
|
14
13
|
|
15
14
|
CACHE_STORE_TYPES.each do |cache_store_types|
|
@@ -72,7 +71,7 @@ describe RailsBrotliCache do
|
|
72
71
|
it "for #write_multi and #read_multi" do
|
73
72
|
values = {
|
74
73
|
"key_1" => big_enough_to_compress_value,
|
75
|
-
"key_2" => "val_2"
|
74
|
+
"key_2" => "val_2",
|
76
75
|
}
|
77
76
|
|
78
77
|
brotli_store.write_multi(values)
|
@@ -87,7 +86,7 @@ describe RailsBrotliCache do
|
|
87
86
|
it "for #fetch_multi" do
|
88
87
|
values = {
|
89
88
|
"key_1" => big_enough_to_compress_value,
|
90
|
-
"key_2" => "val_2"
|
89
|
+
"key_2" => "val_2",
|
91
90
|
}
|
92
91
|
|
93
92
|
brotli_store.fetch_multi("key_1", "key_2") do |key|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spec_helper"
|
4
4
|
|
5
|
-
return unless ENV[
|
5
|
+
return unless ENV["TEST_RAILS_CACHE_STORE"] == "brotli_cache_store"
|
6
6
|
|
7
7
|
describe RailsBrotliCache do
|
8
8
|
subject(:cache_store) do
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spec_helper"
|
4
4
|
|
5
|
-
return unless ENV[
|
5
|
+
return unless ENV["TEST_RAILS_CACHE_STORE"] == "redis_cache_store"
|
6
6
|
|
7
7
|
describe RailsBrotliCache do
|
8
8
|
let(:options) do
|
@@ -24,7 +24,7 @@ describe RailsBrotliCache do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
let(:json) do
|
27
|
-
File.read(
|
27
|
+
File.read("spec/fixtures/sample.json")
|
28
28
|
end
|
29
29
|
|
30
30
|
it "applies more efficient brotli compression" do
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spec_helper"
|
4
4
|
|
5
5
|
describe RailsBrotliCache do
|
6
6
|
subject(:cache_store) do
|
@@ -89,7 +89,7 @@ describe RailsBrotliCache do
|
|
89
89
|
it "works" do
|
90
90
|
values = {
|
91
91
|
"key_1" => big_enough_to_compress_value,
|
92
|
-
"key_2" => 123
|
92
|
+
"key_2" => 123,
|
93
93
|
}
|
94
94
|
|
95
95
|
cache_store.write_multi(values, expires_in: 5.seconds)
|
@@ -107,8 +107,8 @@ describe RailsBrotliCache do
|
|
107
107
|
let(:keys) { %w[key_1 key_2] }
|
108
108
|
let(:response) do
|
109
109
|
{
|
110
|
-
|
111
|
-
|
110
|
+
"key_1" => big_enough_to_compress_value + "key_1",
|
111
|
+
"key_2" => big_enough_to_compress_value + "key_2",
|
112
112
|
}
|
113
113
|
end
|
114
114
|
|
@@ -120,7 +120,7 @@ describe RailsBrotliCache do
|
|
120
120
|
end).to eq response
|
121
121
|
end
|
122
122
|
|
123
|
-
context
|
123
|
+
context "with a complex object that responds to #cache_key" do
|
124
124
|
subject do
|
125
125
|
cache_store.fetch_multi(*keys) do |key|
|
126
126
|
big_enough_to_compress_value + key.id
|
@@ -129,14 +129,14 @@ describe RailsBrotliCache do
|
|
129
129
|
|
130
130
|
let(:keys) do
|
131
131
|
[
|
132
|
-
OpenStruct.new(cache_key:
|
133
|
-
OpenStruct.new(cache_key:
|
132
|
+
OpenStruct.new(cache_key: "key_1", id: "12345"),
|
133
|
+
OpenStruct.new(cache_key: "key_2", id: "54321"),
|
134
134
|
]
|
135
135
|
end
|
136
136
|
let(:response) do
|
137
137
|
{
|
138
|
-
keys[0] => big_enough_to_compress_value +
|
139
|
-
keys[1] => big_enough_to_compress_value +
|
138
|
+
keys[0] => big_enough_to_compress_value + "12345",
|
139
|
+
keys[1] => big_enough_to_compress_value + "54321",
|
140
140
|
}
|
141
141
|
end
|
142
142
|
|
@@ -258,6 +258,58 @@ describe RailsBrotliCache do
|
|
258
258
|
end
|
259
259
|
end
|
260
260
|
|
261
|
+
describe "#delete_multi" do
|
262
|
+
it "removes multiple previously stored cache entries" do
|
263
|
+
cache_store.write("key_1", 1234)
|
264
|
+
cache_store.write("key_2", 5678)
|
265
|
+
cache_store.write("key_3", 9012)
|
266
|
+
|
267
|
+
expect(cache_store.read("key_1")).to eq 1234
|
268
|
+
expect(cache_store.read("key_2")).to eq 5678
|
269
|
+
expect(cache_store.read("key_3")).to eq 9012
|
270
|
+
|
271
|
+
cache_store.delete_multi(["key_1", "key_3"])
|
272
|
+
|
273
|
+
expect(cache_store.read("key_1")).to eq nil
|
274
|
+
expect(cache_store.read("key_2")).to eq 5678
|
275
|
+
expect(cache_store.read("key_3")).to eq nil
|
276
|
+
end
|
277
|
+
|
278
|
+
it "works with complex objects as cache keys" do
|
279
|
+
collection1 = [Post.new(id: 1), Post.new(id: 2)]
|
280
|
+
collection2 = [Post.new(id: 3), Post.new(id: 4)]
|
281
|
+
|
282
|
+
cache_store.write([:views, "controller/action", collection1], "fragment1")
|
283
|
+
cache_store.write([:views, "controller/action", collection2], "fragment2")
|
284
|
+
|
285
|
+
expect(cache_store.read([:views, "controller/action", collection1])).to eq "fragment1"
|
286
|
+
expect(cache_store.read([:views, "controller/action", collection2])).to eq "fragment2"
|
287
|
+
|
288
|
+
cache_store.delete_multi([[:views, "controller/action", collection1]])
|
289
|
+
|
290
|
+
expect(cache_store.read([:views, "controller/action", collection1])).to eq nil
|
291
|
+
expect(cache_store.read([:views, "controller/action", collection2])).to eq "fragment2"
|
292
|
+
end
|
293
|
+
|
294
|
+
it "handles empty array gracefully" do
|
295
|
+
cache_store.write("test-key", 1234)
|
296
|
+
expect(cache_store.read("test-key")).to eq 1234
|
297
|
+
|
298
|
+
cache_store.delete_multi([])
|
299
|
+
|
300
|
+
expect(cache_store.read("test-key")).to eq 1234
|
301
|
+
end
|
302
|
+
|
303
|
+
it "handles non-existent keys gracefully" do
|
304
|
+
cache_store.write("existing-key", 1234)
|
305
|
+
expect(cache_store.read("existing-key")).to eq 1234
|
306
|
+
|
307
|
+
cache_store.delete_multi(["existing-key", "non-existent-key"])
|
308
|
+
|
309
|
+
expect(cache_store.read("existing-key")).to eq nil
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
261
313
|
describe "#clear" do
|
262
314
|
it "clears the cache" do
|
263
315
|
expect(cache_store.write("test-key", 1234))
|
data/spec/spec_helper.rb
CHANGED
@@ -1,28 +1,27 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler/setup"
|
3
3
|
require "active_support"
|
4
4
|
require "active_support/core_ext/hash"
|
5
|
-
require
|
5
|
+
require "redis"
|
6
6
|
|
7
|
-
require_relative
|
7
|
+
require_relative "../lib/rails-brotli-cache"
|
8
8
|
|
9
9
|
$redis = Redis.new
|
10
|
-
$test_rails_cache_store = if ENV[
|
11
|
-
|
12
|
-
elsif ENV[
|
13
|
-
|
14
|
-
elsif ENV[
|
15
|
-
|
16
|
-
else
|
17
|
-
|
18
|
-
end
|
10
|
+
$test_rails_cache_store = if ENV["TEST_RAILS_CACHE_STORE"] == "redis_cache_store"
|
11
|
+
ActiveSupport::Cache::RedisCacheStore.new(redis: $redis)
|
12
|
+
elsif ENV["TEST_RAILS_CACHE_STORE"] == "brotli_cache_store"
|
13
|
+
RailsBrotliCache::Store.new(ActiveSupport::Cache::MemoryStore.new)
|
14
|
+
elsif ENV["TEST_RAILS_CACHE_STORE"] == "memcache_cache_store"
|
15
|
+
ActiveSupport::Cache::ActiveSupport::Cache::MemCacheStore.new
|
16
|
+
else
|
17
|
+
ActiveSupport::Cache::MemoryStore.new
|
18
|
+
end
|
19
19
|
|
20
|
-
require_relative
|
21
|
-
ENV[
|
20
|
+
require_relative "../spec/dummy/config/environment"
|
21
|
+
ENV["RAILS_ROOT"] ||= "#{File.dirname(__FILE__)}../../../spec/dummy"
|
22
22
|
|
23
23
|
RSpec.configure do |config|
|
24
24
|
config.before(:each) do
|
25
25
|
Rails.cache.clear
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-brotli-cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- pawurb
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -136,6 +136,20 @@ dependencies:
|
|
136
136
|
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rufo
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
139
153
|
description: " This gem reduces storage needed for Rails cache by using Brotli compression,
|
140
154
|
which can produce outputs smaller by ~20% and offers better performance than Gzip. "
|
141
155
|
email:
|
@@ -226,7 +240,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
226
240
|
- !ruby/object:Gem::Version
|
227
241
|
version: '0'
|
228
242
|
requirements: []
|
229
|
-
rubygems_version: 3.
|
243
|
+
rubygems_version: 3.5.16
|
230
244
|
signing_key:
|
231
245
|
specification_version: 4
|
232
246
|
summary: Drop-in enhancement for Rails cache, offering better performance and compression
|