Description
With default Nova and Scout setups, model data is sometimes synced to the search index before it's done being saved, which results in the old data being indexed.
- Laravel Version: 6.0.1
- Nova Version: 2.2.0
- PHP Version: 7.2
- Database Driver and Version: MySQL 8.0.16
- Operating System and Version: macOS 10.13
Description
Because Nova updates resources inside a transaction, the saved
model event is sometimes fired before the new data has been committed and persisted to the database. Scout uses the saved
event to trigger updating the search index, so when that update happens, if the new model data hasn't been persisted yet, the search index will be updated with the old data.
See #1759, laravel/scout#152, laravel/framework#8627, laravel/framework#29710, and laravel/ideas#1441.
I would think this is more of a Scout issue, since it would make sense to me to only bother persisting data to a search index once we're absolutely certain that that data is what's saved in our records (i.e. after all transactions are committed), cc @driesvints. Scout hooking updates into the saved
event makes that kind of impossible if you use database transactions. Setting scout.queue
to false
doesn't help here either.
Is it really unreasonable to suggest not using a database transaction to update Nova resources?? Not sure how else we'd get around this.
Steps To Reproduce
- Fresh Laravel, Nova, and Scout installs.
- Set up Algolia so that Scout works and you can verify the data being synce (not necessary if you just want to see what order things happen in locally).
- Create a model observer and set up the
saved
method to dump something out. - Open up
Laravel\Scout\Searchable
and dump something from within thequeueMakeSearchable
method (or fromLaravel\Scout\Jobs\MakeSearchable
).
Watch dumps: queueMakeSearchable
is executed before your own model observer's saved
event.
Ugly workaround
I don't know why this works, but if I register an observer to run only during Nova requests rather than globally, things execute in the order I want. For now, this workaround seems to be holding:
// in Nova-specific model observer
public function saving(Model $model)
{
Model::disableSearchSyncing();
}
public function saved(Model $model)
{
$model->searchable();
}
I'm turning off search syncing on that model during Nova requests, and then making the model searchable manually after the fact.
🙃