Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Searchkick: how does search_index.refresh work with async callbacks?

Tags:

searchkick

In a typical Rails controller, we create a Post model and then redirect to posts_path. The index action uses Searchkick to list Posts.

# In the model
class Post < ApplicationRecord
  searchkick callbacks: :async
end

# In the controller
def index
  @posts = Post.search("*")
end

def create
  Post.create!(post_params)
  redirect_to posts_path
end

However, since Elasticsearch is eventually consistent, sometimes the redirect occur before Searchkick/Elasticsearch indexed that record.

Searchkick's docs state that one could use Post.search_index.refresh to wait for the index to catch up with the new record. So one could write:

def create
  Post.create!(post_params)
  Post.search_index.refresh
  redirect_to posts_path
end

However, sometimes we still redirect to /posts without seeing the newly created record; I think that it's because we're using callbacks: :async, so Searchkick (and Elasticsearch::API::Indices::IndicesClient which is used behind the scenes) has no way to know about the queued Searchkick::ReindexV2Job.

If that's the case, how does one solve this use-case, which is: after the #create or #destroy action have created/destroyed a Searchkick-indexed record, redirect to the #index action making sure that the record is already on the index, when using async callbacks?

like image 707
sandre89 Avatar asked Jan 25 '26 11:01

sandre89


1 Answers

Elasticsearch::API::Indices::IndicesClient which is used behind the scenes) has no way to know about the queued Searchkick::ReindexV2Job.

Your guess is correct. It's possible that your background job hasn't been executed yet, so refreshing the search_index won't help.

To fix the issue, we need to reindex synchronously (in the same thread). Luckily you can change the reindexing strategy of Searchkick callbacks in runtime. In your scenario, I recommend to reindex synchronously via Searchkick.callbacks(:inline):

def create
  # reindex synchonously
  Searchkick.callbacks(:inline) do
    Post.create!(post_params)
  end

  # ensure that all changes are reflected by the ES index
  Post.search_index.refresh

  redirect_to posts_path
end
like image 61
Sepp Avatar answered Jan 28 '26 05:01

Sepp