Sarah Ting

Laravel’s dispatch_sync() and SerializesModel

Learned something about how dispatch_sync() works.

dispatch_sync(new MakeSearchable($this->data));
SQLSTATE[HY000]: General error: 1390 Prepared statement contains too many placeholders (SQL: select *  
   from `...` where `...`.`...` in (4400001, 4400003, 4400010, 4400014, 4400015, 4400017,   
  4400018, 4400022, 4400025, 4400027, 4400030, 4400032, 4400034, 4400035, 4400036, 4400037, 4400038, ...

$this->data contains ~500,000 Eloquent models.

Here’s MakeSearchable

<?php

namespace Laravel\Scout\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\SerializesModels;

class MakeSearchable implements ShouldQueue
{
    use Queueable, SerializesModels;

    public $models;

    public function __construct($models)
    {
        $this->models = $models;
    }

    public function handle()
    {
        if (count($this->models) === 0) {
            return;
        }

        $this->models->first()->searchableUsing()->update($this->models);
    }
}

I assumed that dispatch_sync() would ignore the SerializesModels trait, but apparently it doesn’t — even though the job is being run synchronously, it will still try to serialize and unserialize the models. This might make sense for consistency reasons, but in this scenario does result in reloading all 500k models from the database by ID.

As a workaround, replacing dispatch_sync() with a direct call will skip SerializesModels.

$job = new MakeSearchable($this->data);
$job->handle();