DEV Community

Michel Sánchez Montells
Michel Sánchez Montells

Posted on • Updated on

Unleashing Performance: Silencing Searchkick for Record Updates in Ruby on Rails

You have your model configured for being indexed and searchable with searchkick but sometimes you want to update a record or many records or a bunch of records without triggering searchkick reindex. It is here...

INTRODUCTION

Many articles have been written about how to combine rails, elasticsearch, sidekiq, and redis because this is an almost obvious schema in Ruby on Rails applications.

When you want to have a model indexed and searchable with elastisearch you go mainly with the gem searchkick.

The basic, most used and first option suggested by documentation is:

 class Customer < ApplicationRecord
   searchkick searchable: %i[name lastname],
              filterable: %i[name],
              callbacks: :async

   def search_data
     {
       id: id,
       name: name,
       lastname: lastname
      }
   end
 end
Enter fullscreen mode Exit fullscreen mode

It is supposed also you have sidekiq on the table and the environment variable REDIS_URL.

In this scenario

When you update a customer:

Customer.first.update(name: 'Jack')
Enter fullscreen mode Exit fullscreen mode

then a sidekiq job is triggered for reindex this customer.

PROBLEM

When you update all customers having 30 000 records:

Customer.all.each_with_index{|customer, index| customer.update(name: "Jack-#{index}")
Enter fullscreen mode Exit fullscreen mode

then 30 000 sidekiq jobs are triggered and enqueued for reindex all these customers

SOLUTION

You can update your bunch of customers silencing searchkick and once all updates are executed you can reindex all those customers.
Take a look:

Searchkick.callbacks(false) do
  Customer.all.each_with_index{|customer, index| customer.update(name: "Jack-#{index}")
end
Customer.reindex(mode: :async)
Enter fullscreen mode Exit fullscreen mode

OR

Searchkick.disable_callbacks
Customer.all.each_with_index{|customer, index| customer.update(name: "Jack-#{index}")
Searchkick.enable_callbacks
Customer.reindex(mode: :async)
Enter fullscreen mode Exit fullscreen mode

In this way, once all customers are updated then some sidekiq jobs are being triggered each of them indexing a bunch of customers in a bulk giving you a huge improvement regarding performance and resources.

The second way is especially useful for test:

describe '#has_vacancies?' do
    subject(:event) { create :event, vacancies: 0 }

    before do
      Searchkick.disable_callbacks
    end

    after do
      Searchkick.enable_callbacks
    end

    context 'when vacancies lower than 1' do
      it 'return false' do
        expect(event.vacancies?).to eq false
      end
    end

    context 'when vacancies greater than 0' do
      it 'return true' do
        lesson.update(vacancies: 1)
        expect(event.vacancies?).to eq true
      end
    end
end
Enter fullscreen mode Exit fullscreen mode

Top comments (0)