-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
290: Fix race condition in queued record & document removal r=brunoocasali a=ellnix # Pull Request ## Related issue Fixes #266 ## What does this PR do? The purpose of this PR is to detach the MeiliSearch document deletion process from the ActiveRecord object so that documents corresponding to a record can be deleted even if the record no longer exists in the database. Tests were also added for new functionality and to hopefully prevent regressions. ## PR checklist Please check if your PR fulfills the following requirements: - [X] Does this PR fix an existing issue, or have you listed the changes applied in the PR description (and why they are needed)? - [X] Have you read the contributing guidelines? - [X] Have you made sure that the title is accurate and descriptive of the changes? ## Solution Considerations Please read #266 for full context: - The suggested fix in #266 would not work due to the fact that the primary key of a record in an index can be dynamic (by a user-created method) and may not be reconstructed by the record's database ID alone. In addition, a record may have multiple entries in multiple indexes. - I created a new job so as not to break `MSJob` (although I suspect it would be better if it was replaced with a job dedicated to enqueued indexing, since that's all it does now anyway) - `ActiveJob` needs to somehow serialize the parameters to a job, default serialization (through `GlobalID`) relies on a database entry to reinitialize the record when the job is run - Since the record may no longer exist by the time the job runs, I pass a list of indexes and IDs that _may_ (more on that) belong to the record - I created a new set of `ms_entries` methods whose purpose is to use the current configuration to list every index the record may have a document in, along with the record's primary key in that index - The method does not check `Utilities.indexable?` so it is possible that some of the entries it returns are not actually in MeiliSearch, this is by design since its intention is to be exhaustive and in theory those primary keys _cannot_ belong to another record so deleting them should be ok Co-authored-by: ellnix <[email protected]> Co-authored-by: Bruno Casali <[email protected]>
- Loading branch information
Showing
9 changed files
with
236 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
module MeiliSearch | ||
module Rails | ||
class MSCleanUpJob < ::ActiveJob::Base | ||
queue_as :meilisearch | ||
|
||
def perform(documents) | ||
documents.each do |document| | ||
index = MeiliSearch::Rails.client.index(document[:index_uid]) | ||
|
||
if document[:synchronous] | ||
index.delete_document!(document[:primary_key]) | ||
else | ||
index.delete_document(document[:primary_key]) | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
require 'spec_helper' | ||
|
||
RSpec.describe 'MeiliSearch::Rails::MSCleanUpJob' do | ||
include ActiveJob::TestHelper | ||
|
||
def clean_up_indexes | ||
indexes.each(&:delete_all_documents) | ||
end | ||
|
||
def create_indexed_record | ||
record | ||
|
||
indexes.each do |index| | ||
index.wait_for_task(index.tasks['results'].last['uid']) | ||
end | ||
end | ||
|
||
subject(:clean_up) { MeiliSearch::Rails::MSCleanUpJob } | ||
|
||
let(:record) do | ||
Book.create name: "Moby Dick", author: "Herman Mellville", | ||
premium: false, released: true | ||
end | ||
|
||
let(:record_entries) do | ||
record.ms_entries(true).each { |h| h[:index_uid] += '_test' } | ||
end | ||
|
||
let(:indexes) do | ||
%w[SecuredBook BookAuthor Book].map do |uid| | ||
Book.index(safe_index_uid uid) | ||
end | ||
end | ||
|
||
it 'removes record from all indexes' do | ||
clean_up_indexes | ||
|
||
create_indexed_record | ||
|
||
clean_up.perform_now(record_entries) | ||
|
||
indexes.each do |index| | ||
expect(index.search('*')['hits']).to be_empty | ||
end | ||
end | ||
|
||
context 'when record is already destroyed' do | ||
subject(:record) do | ||
Restaurant.create( | ||
name: "Los Pollos Hermanos", | ||
kind: "Mexican", | ||
description: "Mexican chicken restaurant in Albuquerque, New Mexico.") | ||
end | ||
|
||
let(:indexes) { [Restaurant.index] } | ||
|
||
it 'successfully deletes its document in the index' do | ||
clean_up_indexes | ||
|
||
create_indexed_record | ||
|
||
record.delete # does not run callbacks, unlike #destroy | ||
|
||
clean_up.perform_later(record_entries) | ||
expect { perform_enqueued_jobs }.not_to raise_error | ||
|
||
indexes.each do |index| | ||
expect(index.search('*')['hits']).to be_empty | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.