a2a6331451
`ActiveSupport::MessagePack` is a serializer that integrates with the `msgpack` gem to serialize a variety of Ruby objects. `AS::MessagePack` supports several types beyond the base types that `msgpack` supports, including `Time` and `Range`, as well as Active Support types such as `AS::TimeWithZone` and `AS::HashWithIndifferentAccess`. Compared to `JSON` and `Marshal`, `AS::MessagePack` can provide a performance improvement and message size reduction. For example, when used with `MessageVerifier`: ```ruby # frozen_string_literal: true require "benchmark/ips" require "active_support/all" require "active_support/message_pack" marshal_verifier = ActiveSupport::MessageVerifier.new("secret", serializer: Marshal) json_verifier = ActiveSupport::MessageVerifier.new("secret", serializer: JSON) asjson_verifier = ActiveSupport::MessageVerifier.new("secret", serializer: ActiveSupport::JSON) msgpack_verifier = ActiveSupport::MessageVerifier.new("secret", serializer: ActiveSupport::MessagePack) ActiveSupport::Messages::Metadata.use_message_serializer_for_metadata = true expiry = 1.year.from_now data = { bool: true, num: 123456789, string: "x" * 50 } Benchmark.ips do |x| x.report("Marshal") do marshal_verifier.verify(marshal_verifier.generate(data, expires_at: expiry)) end x.report("JSON") do json_verifier.verify(json_verifier.generate(data, expires_at: expiry)) end x.report("AS::JSON") do asjson_verifier.verify(asjson_verifier.generate(data, expires_at: expiry)) end x.report("MessagePack") do msgpack_verifier.verify(msgpack_verifier.generate(data, expires_at: expiry)) end x.compare! end puts "Marshal size: #{marshal_verifier.generate(data, expires_at: expiry).bytesize}" puts "JSON size: #{json_verifier.generate(data, expires_at: expiry).bytesize}" puts "MessagePack size: #{msgpack_verifier.generate(data, expires_at: expiry).bytesize}" ``` ``` Warming up -------------------------------------- Marshal 1.206k i/100ms JSON 1.165k i/100ms AS::JSON 790.000 i/100ms MessagePack 1.798k i/100ms Calculating ------------------------------------- Marshal 11.748k (± 1.3%) i/s - 59.094k in 5.031071s JSON 11.498k (± 1.4%) i/s - 58.250k in 5.066957s AS::JSON 7.867k (± 2.4%) i/s - 39.500k in 5.024055s MessagePack 17.865k (± 0.8%) i/s - 89.900k in 5.032592s Comparison: MessagePack: 17864.9 i/s Marshal: 11747.8 i/s - 1.52x (± 0.00) slower JSON: 11498.4 i/s - 1.55x (± 0.00) slower AS::JSON: 7866.9 i/s - 2.27x (± 0.00) slower Marshal size: 254 JSON size: 234 MessagePack size: 194 ``` Additionally, `ActiveSupport::MessagePack::CacheSerializer` is a serializer that is suitable for use as an `ActiveSupport::Cache` coder. `AS::MessagePack::CacheSerializer` can serialize `ActiveRecord::Base` instances, including loaded associations. Like `AS::MessagePack`, it provides a performance improvement and payload size reduction: ```ruby # frozen_string_literal: true require "benchmark/ips" require "active_support/message_pack" ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") ActiveRecord::Schema.define do create_table :posts, force: true do |t| t.string :body t.timestamps end create_table :comments, force: true do |t| t.integer :post_id t.string :body t.timestamps end end class Post < ActiveRecord::Base has_many :comments end class Comment < ActiveRecord::Base belongs_to :post end post = Post.create!(body: "x" * 100) 2.times { post.comments.create!(body: "x" * 100) } post.comments.load cache_entry = ActiveSupport::Cache::Entry.new(post) Rails70Coder = ActiveSupport::Cache::Coders::Rails70Coder CacheSerializer = ActiveSupport::MessagePack::CacheSerializer Benchmark.ips do |x| x.report("Rails70Coder") do Rails70Coder.load(Rails70Coder.dump(cache_entry)) end x.report("CacheSerializer") do CacheSerializer.load(CacheSerializer.dump(cache_entry)) end x.compare! end puts "Rails70Coder size: #{Rails70Coder.dump(cache_entry).bytesize}" puts "CacheSerializer size: #{CacheSerializer.dump(cache_entry).bytesize}" ``` ``` Warming up -------------------------------------- Rails70Coder 329.000 i/100ms CacheSerializer 492.000 i/100ms Calculating ------------------------------------- Rails70Coder 3.285k (± 1.7%) i/s - 16.450k in 5.008447s CacheSerializer 4.895k (± 2.4%) i/s - 24.600k in 5.028803s Comparison: CacheSerializer: 4894.7 i/s Rails70Coder: 3285.4 i/s - 1.49x slower Rails70Coder size: 808 CacheSerializer size: 593 ``` Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
189 lines
4.9 KiB
Ruby
189 lines
4.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
source "https://rubygems.org"
|
|
gemspec
|
|
|
|
if RUBY_VERSION < "3"
|
|
gem "minitest", ">= 5.15.0", "< 5.16"
|
|
else
|
|
gem "minitest", ">= 5.15.0"
|
|
end
|
|
|
|
# We need a newish Rake since Active Job sets its test tasks' descriptions.
|
|
gem "rake", ">= 13"
|
|
|
|
gem "sprockets-rails", ">= 2.0.0"
|
|
gem "propshaft", ">= 0.1.7"
|
|
gem "capybara", ">= 3.38"
|
|
gem "selenium-webdriver", ">= 4.0.0"
|
|
|
|
gem "rack-cache", "~> 1.2"
|
|
gem "stimulus-rails"
|
|
gem "turbo-rails"
|
|
gem "jsbundling-rails"
|
|
gem "cssbundling-rails"
|
|
gem "importmap-rails"
|
|
gem "tailwindcss-rails"
|
|
gem "dartsass-rails"
|
|
# require: false so bcrypt is loaded only when has_secure_password is used.
|
|
# This is to avoid Active Model (and by extension the entire framework)
|
|
# being dependent on a binary library.
|
|
gem "bcrypt", "~> 3.1.11", require: false
|
|
|
|
# This needs to be with require false to avoid it being automatically loaded by
|
|
# sprockets.
|
|
gem "terser", ">= 1.1.4", require: false
|
|
|
|
# Explicitly avoid 1.x that doesn't support Ruby 2.4+
|
|
gem "json", ">= 2.0.0"
|
|
|
|
# Workaround until Ruby ships with cgi version 0.3.6 or higher.
|
|
gem "cgi", ">= 0.3.6", require: false
|
|
|
|
group :rubocop do
|
|
gem "rubocop", ">= 1.25.1", require: false
|
|
gem "rubocop-minitest", require: false
|
|
gem "rubocop-packaging", require: false
|
|
gem "rubocop-performance", require: false
|
|
gem "rubocop-rails", require: false
|
|
gem "rubocop-md", require: false
|
|
end
|
|
|
|
group :mdl do
|
|
gem "mdl", require: false
|
|
end
|
|
|
|
group :doc do
|
|
gem "sdoc", ">= 2.6.0"
|
|
gem "rdoc", "~> 6.5"
|
|
gem "redcarpet", "~> 3.2.3", platforms: :ruby
|
|
gem "w3c_validators", "~> 1.3.6"
|
|
gem "rouge"
|
|
gem "rubyzip", "~> 2.0"
|
|
end
|
|
|
|
# Active Support
|
|
gem "dalli", ">= 3.0.1"
|
|
gem "listen", "~> 3.3", require: false
|
|
gem "libxml-ruby", platforms: :ruby
|
|
gem "connection_pool", require: false
|
|
gem "rexml", require: false
|
|
gem "msgpack", ">= 1.7.0", require: false
|
|
|
|
# for railties
|
|
gem "bootsnap", ">= 1.4.4", require: false
|
|
gem "webrick", require: false
|
|
gem "jbuilder", require: false
|
|
gem "web-console", require: false
|
|
|
|
# Action Pack and railties
|
|
rack_version = ENV.fetch("RACK", "~> 2.0") # Change to ~> 3 after #46594 is merged.
|
|
gem "rack", rack_version
|
|
|
|
# Active Job
|
|
group :job do
|
|
gem "resque", require: false
|
|
gem "resque-scheduler", require: false
|
|
gem "sidekiq", require: false
|
|
gem "sucker_punch", require: false
|
|
gem "delayed_job", require: false
|
|
gem "queue_classic", ">= 4.0.0", require: false, platforms: :ruby
|
|
gem "sneakers", require: false
|
|
gem "backburner", require: false
|
|
gem "delayed_job_active_record", require: false
|
|
end
|
|
|
|
# Action Cable
|
|
group :cable do
|
|
gem "puma", ">= 5.0.3", require: false
|
|
|
|
gem "redis", ">= 4.0.1", require: false
|
|
|
|
gem "redis-namespace"
|
|
|
|
gem "websocket-client-simple", github: "matthewd/websocket-client-simple", branch: "close-race", require: false
|
|
end
|
|
|
|
# Active Storage
|
|
group :storage do
|
|
gem "aws-sdk-s3", require: false
|
|
gem "google-cloud-storage", "~> 1.11", require: false
|
|
gem "azure-storage-blob", "~> 2.0", require: false
|
|
|
|
gem "image_processing", "~> 1.2"
|
|
end
|
|
|
|
# Action Mailbox
|
|
gem "aws-sdk-sns", require: false
|
|
gem "webmock"
|
|
|
|
group :ujs do
|
|
gem "webdrivers"
|
|
end
|
|
|
|
# Add your own local bundler stuff.
|
|
local_gemfile = File.expand_path(".Gemfile", __dir__)
|
|
instance_eval File.read local_gemfile if File.exist? local_gemfile
|
|
|
|
group :test do
|
|
gem "minitest-bisect"
|
|
gem "minitest-ci", require: false
|
|
gem "minitest-retry"
|
|
|
|
platforms :mri do
|
|
gem "stackprof"
|
|
gem "debug", ">= 1.1.0", require: false
|
|
end
|
|
|
|
gem "benchmark-ips"
|
|
end
|
|
|
|
platforms :ruby, :windows do
|
|
gem "nokogiri", ">= 1.8.1", "!= 1.11.0"
|
|
|
|
# Needed for compiling the ActionDispatch::Journey parser.
|
|
gem "racc", ">=1.4.6", require: false
|
|
|
|
# Active Record.
|
|
gem "sqlite3", "~> 1.4"
|
|
|
|
group :db do
|
|
gem "pg", "~> 1.3"
|
|
gem "mysql2", "~> 0.5"
|
|
end
|
|
end
|
|
|
|
platforms :jruby do
|
|
if ENV["AR_JDBC"]
|
|
gem "activerecord-jdbcsqlite3-adapter", github: "jruby/activerecord-jdbc-adapter", branch: "master"
|
|
group :db do
|
|
gem "activerecord-jdbcmysql-adapter", github: "jruby/activerecord-jdbc-adapter", branch: "master"
|
|
gem "activerecord-jdbcpostgresql-adapter", github: "jruby/activerecord-jdbc-adapter", branch: "master"
|
|
end
|
|
else
|
|
gem "activerecord-jdbcsqlite3-adapter", ">= 1.3.0"
|
|
group :db do
|
|
gem "activerecord-jdbcmysql-adapter", ">= 1.3.0"
|
|
gem "activerecord-jdbcpostgresql-adapter", ">= 1.3.0"
|
|
end
|
|
end
|
|
end
|
|
|
|
# Gems that are necessary for Active Record tests with Oracle.
|
|
if ENV["ORACLE_ENHANCED"]
|
|
platforms :ruby do
|
|
gem "ruby-oci8", "~> 2.2"
|
|
end
|
|
gem "activerecord-oracle_enhanced-adapter", github: "rsim/oracle-enhanced", branch: "master"
|
|
end
|
|
|
|
gem "tzinfo-data", platforms: [:windows, :jruby]
|
|
gem "wdm", ">= 0.1.0", platforms: [:windows]
|
|
|
|
# The error_highlight gem only works on CRuby 3.1 or later.
|
|
# Also, Rails depends on a new API available since error_highlight 0.4.0.
|
|
# (Note that Ruby 3.1 bundles error_highlight 0.3.0.)
|
|
if RUBY_VERSION >= "3.1"
|
|
gem "error_highlight", ">= 0.4.0", platforms: [:ruby]
|
|
end
|