Skip to content

Instantly share code, notes, and snippets.

@JacobBennett
Last active August 23, 2018 11:06
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JacobBennett/e60d6a932db98985f160146b09455988 to your computer and use it in GitHub Desktop.
Save JacobBennett/e60d6a932db98985f160146b09455988 to your computer and use it in GitHub Desktop.
How Laravel's SerializesModels Trait Could Save Your Bacon

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

published: true
preview: Why does Laravel re-retrieve serialized Model values from the DB for queued jobs? Take a look at this quick example to see how it could save your bacon!
@davecarlson
Copy link

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.

@JacobBennett
Copy link
Author

@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!

@slouma2000
Copy link

  • 1 for the second scenario

@SushilShinde088
Copy link

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

@MikeMnD
Copy link

MikeMnD commented May 2, 2018

Hi Jacob also in the real life scenario when a user is registered we send them confirmation mail to confirm their address and just after that we consider them for truly registered and just after that we can send them Welcome mail. Beside this your article is cool and useful for other use-cases as: app notifications, newsletter subscriptions, marketing campaigns :) and so one. So GJ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment