How Laravel's SerializesModels Trait Could Save Your Bacon

By JacobBennett

When a Laravel Job is dispatched that takes an Eloquent Model as an argument in the constructor, you can use the SerializesModels trait which will only serialize the model identifier. When the job is actually handled, the queue system will automatically re-retrieve the full model instance from the database (docs). Taylor also announced that in Laravel 5.3, you will also be able to do this with Eloquent Collections! (link)

5.3 Collections Serialization

So why is it necessary or helpful for the framework to re-retrieve the model values from the DB at run time instead of just serializing the attributes of the given model or collection? Let's use a contrived example to demonstrate.

Let's say that you create a new job called SendWelcomeEmail that will be dispatched from your RegistrationController each time a new user signs up for your application. Ideally we don't want our user to have to wait for the welcome email to be sent when they sign up, so we make our SendWelcomeEmail job push onto the queue instead. To accomplish this, Laravel magic only requires that our job implements the ShouldQueue interface. Great!

Here is where the paths diverge.

Scenario 1: We already have the email address of our user and we pass through the users email to the job's constructor. Something like

$user = User::find(1);
dispatch(new SendWelcomeEmail($user->email));

Scenario 2: We decide to pass the entire User model into our constructor and use the SerializesModels trait in our SendWelcomeEmail job. Something like

$user = User::find(1);
dispatch(new SendWelcomeEmail($user));

The difference in implementation is nearly indistinguishable, but let's play devils advocate for a minute and see how this might play out.

In Scenario 1, a user signs up, and our job is queued to run. Your application was featured on product hunt this morning however, and you have 100s of emails waiting to be sent in your queue. Your user upon signing up realizes they mistyped their email address, and promptly corrects it in the settings of your app. By the time your queue gets around to the SendWelcomeEmail for this user, the email that was serialized with the job is no longer valid. The user never gets their welcome email and the world stops spinning.

In Scenario 2, all the same steps take place, but when the queued SendWelcomeEmail job finally gets its turn to run, Laravel pulls the latest info for the passed in User, and the email gets sent to the updated email address! Praise be to you almighty dev.

To learn more about Laravel Jobs and utilizing the Queue, check out the amazing Laravel Docs on Queues

Created 1 year ago | Updated 1 week ago

Comments (9)

I tried to comment here, https://gistlog.co/JacobBennett/e60d6a932db98985f160146b09455988, even though I was already logged in on Github. But it didn't allow me. :(

Trying it out myself on gistlog...

Seemed to work for me @renatonascalves. Sorry it didn't work for you? Seems odd. If you want to submit an issue feel free to do so at http://github.com/tightenco/gistlog

Thanks for the walk through! I really didn't understand what this meant before but now it totally makes sense.

@imjohnbon glad to help! One of those things that you don't typically dive into until you get bit by not knowing 😄

but in scenario 2, you have to do an additional database call as it needs to look up the user's details. If you're being hammered by traffic, this is a suboptimal situation. Better to pass the string through, so the jobs need to make the additional calls.

@davecarlson This would be a good problem to have! 👍 You are correct that the second method incurs an additional database call. If your site is getting hit with so much traffic that it can't handle a single request on an indexed column in a single table however, I would say that there might be bigger issues at hand than eliminating a single database call. That is another topic for another day. 😄 Thanks for the comment!

  • 1 for the second scenario

Hi Jacob, I read your article. Its great. I am still not very clear about how to use queues when it comes to passing database instances / models. I keep on getting errors "Type error: Too few arguments to function". Could you please help answer my query on SO?
https://stackoverflow.com/questions/47558236/laravel-how-to-pass-a-single-database-instance-at-a-time-to-the-queue-job-for