Skip to content

Remove the document from Meilisearch when an entity is deleted#156

Open
loevgaard wants to merge 1 commit into
masterfrom
issue-111-remove-entity-document
Open

Remove the document from Meilisearch when an entity is deleted#156
loevgaard wants to merge 1 commit into
masterfrom
issue-111-remove-entity-document

Conversation

@loevgaard

Copy link
Copy Markdown
Member

What

Deleting an indexable entity never removed its document from Meilisearch, so deleted products stayed searchable forever.

RemoveEntity is dispatched from postRemove — at that point the row is already deleted — but the handler then reloaded the entity via find(), got null, and threw UnrecoverableMessageHandlingException. So on async transports the message was marked unrecoverable (orphaned documents accumulate), and on the sync default the exception propagated out of the delete flush and could fail the whole request.

Changes:

  • RemoveEntityHandler no longer reloads the entity. It resolves the affected indexes via IndexRegistry::getByEntity($message->class) and removes the document by its id — the stringified entity id the message already carries (see IndexableAwareTrait).
  • New IdRemovalCapableIndexerInterface::removeByIds(array $ids), implemented by DefaultIndexer, with an instanceof check in the handler so custom indexers stay BC (they're skipped with a logged warning).
  • Batch removal: removeByIds() (and the refactored removeEntities()) issue one deleteDocuments task per scope instead of one deleteDocument HTTP task per entity.
  • EntityListener::postRemove now detach()es the entity from the SplObjectStorage, which was attach-only and grew unbounded in long-running workers.

Testing

  • RemoveEntityHandlerTest: removes by id without reloading the entity (so it no longer throws in the sync setup); skips indexers that can't remove by id.
  • DefaultIndexerTest::it_removes_documents_with_one_batch_delete_task_per_scope: a single deleteDocuments([...]) per scope.
  • EntityListenerTest: after preRemove + postRemove, a RemoveEntity is dispatched and the SplObjectStorage retains no entries.

Closes #111


Stacked on #155 (#128).

@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.66667% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 45.17%. Comparing base (e197d89) to head (00d3831).

Files with missing lines Patch % Lines
src/Indexer/DefaultIndexer.php 56.25% 7 Missing ⚠️
src/Message/Handler/AbstractEntityHandler.php 0.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master     #156      +/-   ##
============================================
+ Coverage     43.86%   45.17%   +1.31%     
- Complexity      729      734       +5     
============================================
  Files           131      131              
  Lines          2387     2406      +19     
============================================
+ Hits           1047     1087      +40     
+ Misses         1340     1319      -21     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread src/Indexer/IdRemovalCapableIndexerInterface.php Outdated
@loevgaard loevgaard force-pushed the issue-128-indexing-logging branch from 33bb045 to eefffde Compare July 10, 2026 17:16
@loevgaard loevgaard force-pushed the issue-111-remove-entity-document branch 2 times, most recently from 26b03ca to 5df71ee Compare July 10, 2026 17:20
Base automatically changed from issue-128-indexing-logging to master July 10, 2026 17:21
RemoveEntity is dispatched from postRemove, after the row is already gone,
but the handler reloaded the entity via find(), got null, and threw
UnrecoverableMessageHandlingException. So async transports marked the message
unrecoverable (orphaned documents) and the sync default failed the delete flush.

- RemoveEntityHandler no longer reloads: it resolves the affected indexes via
  IndexRegistry::getByEntity() and removes the document by its id (the
  stringified entity id the message already carries).
- Add removeByIds() directly to IndexerInterface (no separate capability
  interface — the plugin has no stable release, so BC isn't a concern).
- removeByIds()/removeEntities() issue one batch deleteDocuments task per scope
  instead of one deleteDocument task per entity.
- EntityListener::postRemove detaches the entity from the SplObjectStorage so it
  no longer leaks entries in long-running workers.

Closes #111
@loevgaard loevgaard force-pushed the issue-111-remove-entity-document branch from 5df71ee to 00d3831 Compare July 10, 2026 18:11
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.

[Bug]: Deleting an entity never removes its document from Meilisearch

1 participant