rails-brotli-cache 0.5.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e5fcc9aa5854debba71fab6f5df69615ab2b9edaa6620ae139e7c68c598c0dcb
4
- data.tar.gz: a60ba10b497f50e751ca191ce8e9034bd45b30c93e3dff718a26c14e178ffed9
3
+ metadata.gz: e109b9b356474fb8085b1cceaa892695de997465db4c90872556f76419da8f86
4
+ data.tar.gz: c8422310e9fed160052637a40dc7b1150b938c0f891b3b7b011eacdd11b8e4bb
5
5
  SHA512:
6
- metadata.gz: 066d33ad8b2e12d2fa4242ac120cbd0cd1ceee693619146d72b2dfe95ecd8dfe69b5b01028488a31e5373c5472602c42219cb2e0e749d9a2661c0cbcc26b9cb1
7
- data.tar.gz: a8522dff7f3452c216803cf5a45c62eb0ba1acadc3d4efece1130c35574344d4b2509938a076f78293814c271376b576973135791fc5fdf342240d587a2783cc
6
+ metadata.gz: 6b435443fbf3a6a09baed87b124429e43dcd4d3fbd06cab175a15818b397285aeab96ad0694dc8a2f0e0d91c3478400ba0e3081045e93ca63e275e62626f0e0d
7
+ data.tar.gz: 95af20d56721fbe1e9118b29a0fa1f7dc3fe5825d8c7ee04d77b783b96b405d6b1e765f4d8b63e8668d9414ca1e716cc010e3201d7a93340d35251ebd966f9e8
data/README.md CHANGED
@@ -1,8 +1,17 @@
1
- # Rails Brotli Cache [![Gem Version](https://img.shields.io/gem/v/rails-brotli-cache)](https://badge.fury.io/rb/rails-brotli-cache) [![CircleCI](https://circleci.com/gh/pawurb/rails-brotli-cache.svg?style=svg)](https://circleci.com/gh/pawurb/rails-brotli-cache)
1
+ # Rails Brotli Cache [![Gem Version](https://img.shields.io/gem/v/rails-brotli-cache)](https://badge.fury.io/rb/rails-brotli-cache) [![GH Actions](https://github.com/pawurb/rails-brotli-cache/actions/workflows/ci.yml/badge.svg)](https://github.com/pawurb/rails-brotli-cache/actions)
2
2
 
3
3
  This gem enables support for compressing Ruby on Rails cache entries using the [Brotli compression algorithm](https://github.com/google/brotli). `RailsBrotliCache::Store` offers better compression and performance compared to the default `Rails.cache` Gzip, regardless of the underlying data store. The gem also allows specifying any custom compression algorithm instead of Brotli.
4
4
 
5
- I'm currently working on a post describing the gem in more detail. You can subscribe to [my blog's mailing list](https://eepurl.com/dhuFg5) or [follow me on Twitter](https://twitter.com/_pawurb) to get notified when it's out.
5
+ You can check out [this blog post](https://pawelurbanek.com/rails-brotli-cache) describing the gem in more detail.
6
+
7
+ ## Installation
8
+
9
+ `Gemfile`
10
+
11
+ ```ruby
12
+ gem 'brotli' # an optional dependency, other compressors are supported
13
+ gem 'rails-brotli-cache'
14
+ ```
6
15
 
7
16
  ## Benchmarks
8
17
 
@@ -130,10 +139,21 @@ config.cache_store = RailsBrotliCache::Store.new(
130
139
  ```
131
140
 
132
141
  ```ruby
142
+
143
+ class ZSTDCompressor
144
+ def self.deflate(payload)
145
+ ::Zstd.compress(payload, 10)
146
+ end
147
+
148
+ def self.inflate(payload)
149
+ ::Zstd.decompress(payload)
150
+ end
151
+ end
152
+
133
153
  Rails.cache.write('test-key', json, compressor_class: Snappy)
134
154
  ```
135
155
 
136
- This config expects a class which defines two class methods `inflate` and `deflate`. It allows you to instead use for example a [Google Snappy algorithm](https://github.com/miyucy/snappy) offering even better performance for the cost of worse compresion ratios. Optionally, you can define a custom class wrapping any compression library.
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.
137
157
 
138
158
  ## Testing
139
159
 
data/benchmarks/Gemfile CHANGED
@@ -1,5 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ gem 'brotli'
3
4
  gem 'rails-brotli-cache', path: "../"
4
5
  gem 'redis'
5
6
  gem 'dalli'
7
+ gem 'zstd-ruby'
data/benchmarks/main.rb CHANGED
@@ -1,30 +1,62 @@
1
- require "active_support"
2
- require "active_support/core_ext/hash"
1
+ require 'active_support'
2
+ require 'active_support/core_ext/hash'
3
3
  require 'net/http'
4
+ require 'brotli'
4
5
  require 'rails-brotli-cache'
6
+ require 'benchmark'
7
+ require 'zstd-ruby'
8
+
9
+ class ZSTDCompressor
10
+ def self.deflate(payload)
11
+ ::Zstd.compress(payload, 10)
12
+ end
13
+
14
+ def self.inflate(payload)
15
+ ::Zstd.decompress(payload)
16
+ end
17
+ end
5
18
 
6
19
  memory_cache = ActiveSupport::Cache::MemoryStore.new(compress: true) # memory store does not use compression by default
7
20
  brotli_memory_cache = RailsBrotliCache::Store.new(memory_cache)
21
+ zstd_memory_cache = RailsBrotliCache::Store.new(memory_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
22
+
8
23
  redis_cache = ActiveSupport::Cache::RedisCacheStore.new
9
24
  brotli_redis_cache = RailsBrotliCache::Store.new(redis_cache)
25
+ zstd_redis_cache = RailsBrotliCache::Store.new(redis_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
26
+
10
27
  memcached_cache = ActiveSupport::Cache::MemCacheStore.new
11
28
  brotli_memcached_cache = RailsBrotliCache::Store.new(memcached_cache)
29
+ zstd_memcached_cache = RailsBrotliCache::Store.new(memcached_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
30
+
12
31
  file_cache = ActiveSupport::Cache::FileStore.new('/tmp')
13
32
  brotli_file_cache = RailsBrotliCache::Store.new(file_cache)
33
+ zstd_file_cache = RailsBrotliCache::Store.new(file_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
14
34
 
15
35
  json_uri = URI("https://raw.githubusercontent.com/pawurb/rails-brotli-cache/main/spec/fixtures/sample.json")
16
36
  json = Net::HTTP.get(json_uri)
17
37
 
18
38
  puts "Uncompressed JSON size: #{json.size}"
19
39
  redis_cache.write("gz-json", json)
20
- gzip_json_size = redis_cache.redis.get("gz-json").size
40
+ gzip_json_size = redis_cache.redis.with do |conn|
41
+ conn.get("gz-json").size
42
+ end
21
43
  puts "Gzip JSON size: #{gzip_json_size}"
22
44
  brotli_redis_cache.write("json", json)
23
- br_json_size = redis_cache.redis.get("br-json").size
45
+ br_json_size = redis_cache.redis.with do |conn|
46
+ conn.get("br-json").size
47
+ end
24
48
  puts "Brotli JSON size: #{br_json_size}"
25
49
  puts "~#{((gzip_json_size - br_json_size).to_f / gzip_json_size.to_f * 100).round}% improvment"
26
50
  puts ""
27
51
 
52
+ zstd_redis_cache.write("json", json)
53
+ zs_json_size = redis_cache.redis.with do |conn|
54
+ conn.get("zs-json").size
55
+ end
56
+ puts "ZSTD JSON size: #{zs_json_size}"
57
+ puts "~#{((gzip_json_size - zs_json_size).to_f / gzip_json_size.to_f * 100).round}% improvment"
58
+ puts ""
59
+
28
60
  iterations = 100
29
61
 
30
62
  Benchmark.bm do |x|
@@ -42,6 +74,13 @@ Benchmark.bm do |x|
42
74
  end
43
75
  end
44
76
 
77
+ x.report("zstd_memory_cache") do
78
+ iterations.times do
79
+ zstd_memory_cache.write("test", json)
80
+ zstd_memory_cache.read("test")
81
+ end
82
+ end
83
+
45
84
  x.report("redis_cache") do
46
85
  iterations.times do
47
86
  redis_cache.write("test", json)
@@ -56,6 +95,13 @@ Benchmark.bm do |x|
56
95
  end
57
96
  end
58
97
 
98
+ x.report("zstd_redis_cache") do
99
+ iterations.times do
100
+ zstd_redis_cache.write("test", json)
101
+ zstd_redis_cache.read("test")
102
+ end
103
+ end
104
+
59
105
  x.report("memcached_cache") do
60
106
  iterations.times do
61
107
  memcached_cache.write("test", json)
@@ -70,6 +116,13 @@ Benchmark.bm do |x|
70
116
  end
71
117
  end
72
118
 
119
+ x.report("zstd_memcached_cache") do
120
+ iterations.times do
121
+ zstd_memcached_cache.write("test", json)
122
+ zstd_memcached_cache.read("test")
123
+ end
124
+ end
125
+
73
126
  x.report("file_cache") do
74
127
  iterations.times do
75
128
  file_cache.write("test", json)
@@ -83,4 +136,11 @@ Benchmark.bm do |x|
83
136
  brotli_file_cache.read("test")
84
137
  end
85
138
  end
139
+
140
+ x.report("zstd_file_cache") do
141
+ iterations.times do
142
+ zstd_file_cache.write("test", json)
143
+ zstd_file_cache.read("test")
144
+ end
145
+ end
86
146
  end
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'active_support/cache'
4
- require 'brotli'
4
+ begin
5
+ require 'brotli'
6
+ rescue LoadError
7
+ end
5
8
 
6
9
  module RailsBrotliCache
7
10
  class Store < ::ActiveSupport::Cache::Store
@@ -112,8 +115,10 @@ module RailsBrotliCache
112
115
  @core_store.fetch_multi(
113
116
  *names, options.merge(compress: false)
114
117
  ) do |name|
115
- compressed(yield(name), options)
116
- end
118
+ compressed(yield(source_cache_key(name)), options)
119
+ end.map do |key, val|
120
+ [source_cache_key(key), uncompressed(val, options)]
121
+ end.to_h
117
122
  end
118
123
 
119
124
  def exist?(name, options = {})
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsBrotliCache
4
- VERSION = "0.5.0"
4
+ VERSION = "0.6.1"
5
5
  end
@@ -16,7 +16,7 @@ Gem::Specification.new do |gem|
16
16
  gem.require_paths = ["lib"]
17
17
  gem.license = "MIT"
18
18
  gem.add_dependency "activesupport"
19
- gem.add_dependency "brotli"
19
+ gem.add_development_dependency "brotli"
20
20
  gem.add_development_dependency "rspec"
21
21
  gem.add_development_dependency "railties"
22
22
  gem.add_development_dependency "activemodel"
@@ -13,6 +13,10 @@ describe RailsBrotliCache do
13
13
  ]
14
14
 
15
15
  CACHE_STORE_TYPES.each do |cache_store_types|
16
+ let(:big_enough_to_compress_value) do
17
+ SecureRandom.hex(2048)
18
+ end
19
+
16
20
  describe "Brotli cache has the same API as #{cache_store_types[0].class}" do
17
21
  subject(:brotli_store) do
18
22
  RailsBrotliCache::Store.new(cache_store_types[0])
@@ -32,7 +36,7 @@ describe RailsBrotliCache do
32
36
 
33
37
  it "for #read and #write" do
34
38
  int_val = 123
35
- expect(brotli_store.write("int_val_key", int_val).class).to eq(standard_cache.write("int_val_key", int_val).class)
39
+ expect(brotli_store.write("int_val_key", big_enough_to_compress_value).class).to eq(standard_cache.write("int_val_key", big_enough_to_compress_value).class)
36
40
  expect(brotli_store.read("int_val_key")).to eq(standard_cache.read("int_val_key"))
37
41
 
38
42
  str_val = "str"
@@ -55,16 +59,15 @@ describe RailsBrotliCache do
55
59
  end
56
60
 
57
61
  it "for #fetch" do
58
- val = "123"
59
- expect(brotli_store.fetch("val_key") { val }).to eq(standard_cache.fetch("val_key") { val })
60
- expect(brotli_store.fetch("val_key", force: true) { val }).to eq(standard_cache.fetch("val_key", force: true) { val })
62
+ expect(brotli_store.fetch("val_key") { big_enough_to_compress_value }).to eq(standard_cache.fetch("val_key") { big_enough_to_compress_value })
63
+ expect(brotli_store.fetch("val_key", force: true) { big_enough_to_compress_value }).to eq(standard_cache.fetch("val_key", force: true) { big_enough_to_compress_value })
61
64
  expect(brotli_store.fetch("val_key")).to eq(standard_cache.fetch("val_key"))
62
65
  end
63
66
 
64
67
  it "for #write_multi and #read_multi" do
65
68
  values = {
66
69
  "key_1" => "val_1",
67
- "key_2" => "val_2"
70
+ "key_2" => big_enough_to_compress_value
68
71
  }
69
72
 
70
73
  brotli_store.write_multi(values)
@@ -78,7 +81,7 @@ describe RailsBrotliCache do
78
81
 
79
82
  it "for #fetch_multi" do
80
83
  values = {
81
- "key_1" => "val_1",
84
+ "key_1" => big_enough_to_compress_value,
82
85
  "key_2" => "val_2"
83
86
  }
84
87
 
@@ -98,9 +98,22 @@ describe RailsBrotliCache do
98
98
  end
99
99
 
100
100
  describe "fetch_multi" do
101
+ subject do
102
+ cache_store.fetch_multi(*keys) do |key|
103
+ big_enough_to_compress_value + key
104
+ end
105
+ end
106
+
107
+ let(:keys) { %w[key_1 key_2] }
108
+ let(:response) do
109
+ {
110
+ 'key_1' => big_enough_to_compress_value + 'key_1',
111
+ 'key_2' => big_enough_to_compress_value + 'key_2'
112
+ }
113
+ end
114
+
101
115
  it "works" do
102
- cache_store.fetch_multi("key_1", "key_2", expires_in: 5.seconds) { big_enough_to_compress_value }
103
- expect(cache_store.read("key_1")).to eq big_enough_to_compress_value
116
+ expect(subject).to eq response
104
117
  end
105
118
  end
106
119
 
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.5.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - pawurb
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-19 00:00:00.000000000 Z
11
+ date: 2023-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -31,7 +31,7 @@ dependencies:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
- type: :runtime
34
+ type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
@@ -226,7 +226,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
226
226
  - !ruby/object:Gem::Version
227
227
  version: '0'
228
228
  requirements: []
229
- rubygems_version: 3.4.10
229
+ rubygems_version: 3.3.7
230
230
  signing_key:
231
231
  specification_version: 4
232
232
  summary: Drop-in enhancement for Rails cache, offering better performance and compression