Dispatching After Commit0:00
When it comes to best practices, there are several things we need to consider while designing and dispatching reliable queue jobs. Let's start with a problem that happens when we dispatch jobs from inside a database transaction. Here we are dispatching a SendWelcomeEmail job inside a database transaction. The transaction will commit after the closure is invoked. That means dispatching the job will happen before the transaction commits. And if a worker is available, it may pick the job immediately before the transaction commits. Now when this job runs and you query the users table to find the user we just created, the query will return null, because the transaction hasn't committed yet.
Now when this job runs and you query the users table to find the User we just created, the query will return null, because the transaction hasn't committed yet. To solve this problem, we can use the afterCommit method here while dispatching the job. This will delay dispatching the job till after the transaction commits, instead of before the transaction commits. It will also configure Laravel to discard the dispatching if the transaction was rolled back. So if anything went wrong and the transaction didn't commit, the sendWelcomeEmail job will not get dispatched. We can also enforce this behavior globally by updating the queue.php configuration file.
Enforcing afterCommit Globally1:20
will not get dispatched. We can also enforce this behavior globally by updating the queue.php configuration file. So if we go to queue.php configuration file and under the connection that we are using, we can configure the afterCommit property here and configure it to true. Now any job that gets dispatched to our connection here will wait until any database transactions open are committed. And this is quite handy and prevents a lot of confusing bugs. Now let's take a look at a few things to consider while designing queue jobs. Let's take a look at this DeployProjectJob. While dispatching the job to the queue, Laravel will serialize the job object so it can be
Minimizing Job Serialization1:59
Let's take a look at this deploy project job. While dispatching the job to the queue, Laravel will serialize the job object so it can be stored in the queue as a string. A job object that has complex dependencies will consume a lot of resources while being serialized and unserialized. And it will also occupy more space to be stored. And of course it will take more time to move the job to and from the queue store. In our job here we have multiple complex dependencies, the container instance and an Eloquent model instance. We need to get rid of those.
instance. We need to get rid of those. We use the container to resolve a dependency called deployer. So instead of using the container that's passed to the constructor, we can use the app helper to get an instance of the container inside the handle method. By doing this we can drop this dependency, the container dependency. Great. And as for the Eloquent model, do you see the SerializeModel trait here? It's added by default to all jobs that are created using the php artisan make:job command. When this trait is used, Eloquent models will be converted to a simple PHP object while
It's added by default to all jobs that are created using the php artisan make:job command. When this trait is used, Eloquent models will be converted to a simple PHP object while the job is being serialized. That sample object will hold a reference to the model type and the model key in the database. Workers will retrieve the original model later when the job runs. So now this job has light dependencies. We drop the container instance from the constructor and as for the Eloquent model, as we explained, it's swapped with another instance that's much more simpler and more light. Perfect. Let's look at the next problem with this job.
Making Jobs Self-Contained3:45
Perfect. Let's look at the next problem with this job. Do you see that we grab the last commit hash inside the handle method here? That means that we'll deploy the project, when the job runs, we'll deploy the project using the last commit hash when the job was processed, not when it was pushed. If you can imagine a scenario where the User changed the color of a pattern to green and then deployed and then changed it to blue, they'd expect the deployment to give them a green pattern. But because we grab the latest commit hash from inside the handle method, we're going to grab the commit hash that turned the pattern into blue, not green.
But because we grab the latest commit hash from inside the handle method, we're going to grab the commit hash that turned the pattern into blue, not green. To fix this we need to make sure that the job is self-contained. That means that it has everything it needs to run without relying on any external state. To do that we are going to require the latest commit hash as a job dependency in the constructor. So here we are going to require the latest commit hash and declare the property. And instead of getting the latest commit hash from the site instance, we are going to use the property. Now the job will deploy the latest commit hash that was found when the user dispatched the job, not when the worker picked it up.
Encrypting Sensitive Job Data5:04
Now the job will deploy the latest commit hash that was found when the user dispatched the job, not when the worker picked it up. Another thing to keep in mind is that storing sensitive data in the job object exposes it to whatever entity that has access to the QStore. Let's take a look at another job here, it's called TestJob. This job accepts a secret in the constructor. To show you the problem let's dispatch this job. So we go to the web.php routes file. Let's clear it first and then dispatch the TestJob. So this job dispatch and then we are going to pass the secret.
Let's clear it first and then dispatch the test job. So this job dispatch and then we are going to pass the secret. This is the secret. Now let's go to the browser and dispatch the job. Then we go to the Queue store and see the payload here. And if you look closely we can see the secret that we passed to the job while dispatching it. That's not good. To deal with this problem we may implement the ShouldBeEncrypted interface on the job. So let's go to the job class and implement the ShouldBeEncrypted interface.
To deal with this problem we may implement the ShouldBeEncrypted interface on the Job. So let's go to the Job class and implement the ShouldBeEncrypted interface. Now Laravel is going to encrypt the payload of the job. Let's dispatch it again to see this in action. And if we go to the Queue store and check the payload of the second job that we dispatched, you can see that the payload is encrypted and the secret is not visible to anyone. Only the Laravel application may decrypt this payload and extract the information stored.
