rails-brotli-cache 0.2.0 → 0.2.2

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: 01d8f09dfdea5ea7f2c19ce63e44b88322b319bfcda33f9efeeb679710e78f87
4
- data.tar.gz: bd6df6fadfd6206ed598dab1ced924d59e5c27da6f1c8a0eaeed434f934219c6
3
+ metadata.gz: ed8813c2a9849358eb4d1756cd39eda4acf03846ea166880b956d9c630a5f3ee
4
+ data.tar.gz: cdff030d0d6bdd7e2b7790c5aea0441ecc89e184165c38e899dc5abdc7f5c900
5
5
  SHA512:
6
- metadata.gz: 7919aaad175395d8494f20f1e40b6b5d96e6bd68a3aa60036dd0aa9682b8251e06139fa56748cfe4a5660be3aea5f09f9b7609806336b47b954cefadca227c1d
7
- data.tar.gz: 41ddc8e815662f7f0e9037e5b0beaeacf48cb62eac1c05380b3be44664ed951256cf185d2ecc730f406f7b8a7ee615cad782e68f037907a37b56a1a658766f1d
6
+ metadata.gz: 5bf99730b2b31ed9591157fe75764fb15c17cf84cfd664d148a339e8552ed27dc62512cdff39f84552bc151aa4105d8720546eef38aa9e2da0552427d05ab86f
7
+ data.tar.gz: 7aa77827f595e73d55dc838ac8c6159a3f0f9138ed5bcdf57b2a0876060e01b66704dfd93f2eb8dc6502d109a0933f825bfc9d422858cbb786b03a75569f32d6
data/README.md CHANGED
@@ -9,8 +9,8 @@ This gem enables support for compressing Ruby on Rails cache entries using the [
9
9
  Brotli cache works as a proxy layer wrapping the underlying cache data store.
10
10
 
11
11
  ```ruby
12
- default_cache = ActiveSupport::Cache::RedisCacheStore.new(redis: $redis)
13
- brotli_cache = RailsBrotliCache::Store.new(default_cache)
12
+ redis_cache = ActiveSupport::Cache::RedisCacheStore.new
13
+ brotli_redis_cache = RailsBrotliCache::Store.new(redis_cache)
14
14
  ```
15
15
 
16
16
  **~25%** better compression of a sample JSON object:
@@ -18,8 +18,8 @@ brotli_cache = RailsBrotliCache::Store.new(default_cache)
18
18
  ```ruby
19
19
  json = File.read("sample.json") # sample 435kb JSON text
20
20
  json.size # => 435662
21
- default_cache.write("json", json)
22
- brotli_cache.write("json", json)
21
+ redis_cache.write("json", json)
22
+ brotli_redis_cache.write("json", json)
23
23
 
24
24
  ## Check the size of cache entry stored in Redis
25
25
  $redis.get("json").size # => 31698
@@ -30,8 +30,8 @@ $redis.get("br-json").size # => 24058
30
30
 
31
31
  ```ruby
32
32
  users = User.limit(100).to_a # 100 ActiveRecord objects
33
- default_cache.write("users", users)
34
- brotli_cache.write("users", users)
33
+ redis_cache.write("users", users)
34
+ brotli_redis_cache.write("users", users)
35
35
  $redis.get("users").size # => 12331
36
36
  $redis.get("br-users").size # => 10299
37
37
  ```
@@ -39,27 +39,44 @@ $redis.get("br-users").size # => 10299
39
39
  **~25%** faster performance for reading/writing a larger JSON file:
40
40
 
41
41
  ```ruby
42
- json = File.read("sample.json") # sample 435kb JSON text
42
+ json = File.read("sample.json") # sample ~1mb JSON text
43
43
 
44
44
  Benchmark.bm do |x|
45
- x.report("default_cache") do
46
- 1000.times do
47
- default_cache.write("test", json)
48
- default_cache.read("test")
45
+ x.report("redis_cache") do
46
+ 100.times do
47
+ redis_cache.write("test", json)
48
+ redis_cache.read("test")
49
49
  end
50
50
  end
51
51
 
52
- x.report("brotli_cache") do
53
- 1000.times do
54
- brotli_cache.write("test", json)
55
- brotli_cache.read("test")
52
+ x.report("brotli_redis_cache") do
53
+ 100.times do
54
+ brotli_redis_cache.write("test", json)
55
+ brotli_redis_cache.read("test")
56
56
  end
57
57
  end
58
+
59
+ # ...
58
60
  end
59
61
 
60
- # user system total real
61
- # default_cache 5.177678 0.216435 5.394113 ( 8.296072)
62
- # brotli_cache 3.513312 0.323601 3.836913 ( 6.114179)
62
+ # memory_cache 2.081221 0.051615 2.132836 ( 2.132877)
63
+ # brotli_memory_cache 1.134411 0.032996 1.167407 ( 1.167418)
64
+ # redis_cache 1.782225 0.049936 1.832161 ( 2.523317)
65
+ # brotli_redis_cache 1.218365 0.051084 1.269449 ( 1.850894)
66
+ # memcached_cache 1.766268 0.045351 1.811619 ( 2.504233)
67
+ # brotli_memcached_cache 1.194646 0.051750 1.246396 ( 1.752982)
68
+ ```
69
+
70
+ Regardless of the underlying data store, Brotli cache offers between 20%-40% performance improvment.
71
+
72
+ You can run the benchmarks yourself by executing:
73
+
74
+ ```ruby
75
+ cp docker-compose.yml.sample docker-compose.yml
76
+ docker compose up -d
77
+ cd benchmarks
78
+ bundle install
79
+ ruby main.rb
63
80
  ```
64
81
 
65
82
  ## Configuration
@@ -84,12 +101,13 @@ config.cache_store = RailsBrotliCache::Store.new(
84
101
  )
85
102
  ```
86
103
 
87
- Gem appends `br-` to the cache key names to prevent conflicts with previously saved cache entries. You can disable this behaviour by adding the following initializer file:
88
-
89
- `app/config/initializers/rails-brotli-cache.rb`
104
+ Gem appends `br-` to the cache key names to prevent conflicts with previously saved cache entries. You can disable this behaviour by passing `{ prefix: nil }` during initialization:
90
105
 
91
106
  ```ruby
92
- Rails.cache.disable_prefix!
107
+ config.cache_store = RailsBrotliCache::Store.new(
108
+ ActiveSupport::Cache::MemoryStore.new,
109
+ { prefix: nil }
110
+ )
93
111
  ```
94
112
 
95
113
  ## Testing
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails-brotli-cache'
@@ -0,0 +1,69 @@
1
+ require 'rails'
2
+ require 'net/http'
3
+ require 'rails-brotli-cache'
4
+
5
+ memory_cache = ActiveSupport::Cache::MemoryStore.new(compress: true) # memory store does not use compression by default
6
+ brotli_memory_cache = RailsBrotliCache::Store.new(memory_cache)
7
+ redis_cache = ActiveSupport::Cache::RedisCacheStore.new
8
+ brotli_redis_cache = RailsBrotliCache::Store.new(redis_cache)
9
+ memcached_cache = ActiveSupport::Cache::MemCacheStore.new
10
+ brotli_memcached_cache = RailsBrotliCache::Store.new(memcached_cache)
11
+
12
+ json_uri = URI("https://raw.githubusercontent.com/pawurb/rails-brotli-cache/main/spec/fixtures/sample.json")
13
+ json = Net::HTTP.get(json_uri)
14
+
15
+ puts "Uncompressed JSON size: #{json.size}"
16
+ redis_cache.write("gz-json", json)
17
+ gzip_json_size = redis_cache.redis.get("gz-json").size
18
+ puts "Gzip JSON size: #{gzip_json_size}"
19
+ brotli_redis_cache.write("json", json)
20
+ br_json_size = redis_cache.redis.get("br-json").size
21
+ puts "Brotli JSON size: #{br_json_size}"
22
+ puts "~#{((gzip_json_size - br_json_size).to_f / gzip_json_size.to_f * 100).round}% improvment"
23
+ puts ""
24
+
25
+ iterations = 100
26
+
27
+ Benchmark.bm do |x|
28
+ x.report("memory_cache") do
29
+ iterations.times do
30
+ memory_cache.write("test", json)
31
+ memory_cache.read("test")
32
+ end
33
+ end
34
+
35
+ x.report("brotli_memory_cache") do
36
+ iterations.times do
37
+ brotli_memory_cache.write("test", json)
38
+ brotli_memory_cache.read("test")
39
+ end
40
+ end
41
+
42
+ x.report("redis_cache") do
43
+ iterations.times do
44
+ redis_cache.write("test", json)
45
+ redis_cache.read("test")
46
+ end
47
+ end
48
+
49
+ x.report("brotli_redis_cache") do
50
+ iterations.times do
51
+ brotli_redis_cache.write("test", json)
52
+ brotli_redis_cache.read("test")
53
+ end
54
+ end
55
+
56
+ x.report("memcached_cache") do
57
+ iterations.times do
58
+ memcached_cache.write("test", json)
59
+ memcached_cache.read("test")
60
+ end
61
+ end
62
+
63
+ x.report("brotli_memcached_cache") do
64
+ iterations.times do
65
+ brotli_memcached_cache.write("test", json)
66
+ brotli_memcached_cache.read("test")
67
+ end
68
+ end
69
+ end
@@ -9,9 +9,15 @@ module RailsBrotliCache
9
9
  COMPRESS_QUALITY = ENV.fetch("BR_CACHE_COMPRESS_QUALITY", 5).to_i
10
10
  MARK_BR_COMPRESSED = "\x02".b
11
11
 
12
+ attr_reader :core_store
13
+
12
14
  def initialize(core_store, options = {})
13
15
  @core_store = core_store
14
- @prefix = "br-"
16
+ @prefix = if options.key?(:prefix)
17
+ options.fetch(:prefix)
18
+ else
19
+ "br-"
20
+ end
15
21
  end
16
22
 
17
23
  def fetch(name, options = nil, &block)
@@ -74,10 +80,6 @@ module RailsBrotliCache
74
80
  @core_store.clear
75
81
  end
76
82
 
77
- def disable_prefix!
78
- @@prefix = nil
79
- end
80
-
81
83
  private
82
84
 
83
85
  def cache_key(name)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsBrotliCache
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.2"
5
5
  end
@@ -73,12 +73,4 @@ describe RailsBrotliCache do
73
73
  expect(cache_store.read("test-key")).to eq nil
74
74
  end
75
75
  end
76
-
77
- describe "disable_prefix!" do
78
- it "saves brotli cache entries without `br-` prefix" do
79
- cache_store.disable_prefix!
80
- cache_store.fetch("test-key") { 123 }
81
- cache_store.instance_variable_set(:@prefix, "br-")
82
- end
83
- end
84
76
  end
@@ -5,9 +5,14 @@ require 'spec_helper'
5
5
  return unless ENV['RAILS_CACHE_STORE'] == 'redis_cache_store'
6
6
 
7
7
  describe RailsBrotliCache do
8
+ let(:options) do
9
+ {}
10
+ end
11
+
8
12
  subject(:cache_store) do
9
13
  RailsBrotliCache::Store.new(
10
- ActiveSupport::Cache::RedisCacheStore.new(redis: $redis)
14
+ ActiveSupport::Cache::RedisCacheStore.new(redis: $redis),
15
+ options
11
16
  )
12
17
  end
13
18
 
@@ -27,4 +32,26 @@ describe RailsBrotliCache do
27
32
  cache_store.write("test-key", json)
28
33
  expect($redis.get("gz-test-key").size > $redis.get("br-test-key").size).to eq true
29
34
  end
35
+
36
+ describe "disable_prefix" do
37
+ context "default prefix" do
38
+ it "appends 'br-' prefix" do
39
+ cache_store.fetch("test-key") { 123 }
40
+ expect($redis.get("test-key")).to eq nil
41
+ expect($redis.get("br-test-key")).to be_present
42
+ end
43
+ end
44
+
45
+ context "no prefix" do
46
+ let(:options) do
47
+ { prefix: nil }
48
+ end
49
+
50
+ it "saves brotli cache entries without `br-` prefix" do
51
+ cache_store.fetch("test-key") { 123 }
52
+ expect($redis.get("br-test-key")).to eq nil
53
+ expect($redis.get("test-key")).to be_present
54
+ end
55
+ end
56
+ end
30
57
  end
@@ -40,6 +40,12 @@ describe RailsBrotliCache do
40
40
  end
41
41
  end
42
42
 
43
+ describe "#core_store" do
44
+ it "exposes the underlying data store" do
45
+ expect(cache_store.core_store.class).to eq ActiveSupport::Cache::MemoryStore
46
+ end
47
+ end
48
+
43
49
  describe "#read and #write" do
44
50
  it "reads values stored in Rails cache with a prefix" do
45
51
  expect(cache_store.read("test-key")).to eq nil
@@ -67,12 +73,4 @@ describe RailsBrotliCache do
67
73
  expect(cache_store.read("test-key")).to eq nil
68
74
  end
69
75
  end
70
-
71
- describe "disable_prefix!" do
72
- it "saves brotli cache entries without `br-` prefix" do
73
- cache_store.disable_prefix!
74
- cache_store.fetch("test-key") { 123 }
75
- cache_store.instance_variable_set(:@prefix, "br-")
76
- end
77
- end
78
76
  end
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.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - pawurb
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-18 00:00:00.000000000 Z
11
+ date: 2023-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -108,6 +108,8 @@ files:
108
108
  - LICENSE.txt
109
109
  - README.md
110
110
  - Rakefile
111
+ - benchmarks/Gemfile
112
+ - benchmarks/main.rb
111
113
  - docker-compose.yml.sample
112
114
  - lib/rails-brotli-cache.rb
113
115
  - lib/rails-brotli-cache/store.rb