Skip to content

Conversation

@Bhacaz
Copy link

@Bhacaz Bhacaz commented May 7, 2025

Hi, I would like to suggest a small change that has a big impact on performance.

Currently, instantiating the encryptor, especially due to ActiveSupport::KeyGenerator#generate_key, is a CPU-intensive operation. This can lead to significant overhead if an encryptor is initialized repeatedly for the same attribute type.

Rails attribute types, like ActiveRecordEncryptedString::Type, are (if I understand it correctly) typically instantiated once per attribute definition (e.g., attribute :secret_field, :encrypted_string). This PR leverages this by memoizing the encryptor instance variable (e.g., using @encryptor ||= ...).

With the help of the specs I benchmark that change

it 'benchmark' do
  Benchmark.bm do |x|
    x.report('encrypt') do
      100.times do |i|
        dummy_klass.create!(plain: plain, encrypted: "test#{i}")
      end
    end
    x.report('decrypt') do
      dummy_klass.pluck(:encrypted)
    end
  end
end

# Without
#              user     system      total        real
# encrypt  6.315960   0.063629   6.379589 (  6.431360)
# decrypt  3.325287   0.023737   3.349024 (  3.364617)
#
# With memorization
#              user     system      total        real
# encrypt  0.126073   0.020950   0.147023 (  0.147913)
# decrypt  0.005078   0.001927   0.007005 (  0.007034)

This how I found out

Details

it 'flamegraph' do
  100.times do |i|
    dummy_klass.create!(plain: plain, encrypted: "test#{i}")
  end
  flamegraph { dummy_klass.pluck(:encrypted) }
end

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant