تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Dispatching Queueable Jobs0:00

So, we've gone down the rabbit hole to figure out what happens when you dispatch a job that is not queueable. Let's do one second pass, but this time, we're going to return the shouldQueue interface. Now, granted, I know it's not the most fun thing in the world to source dive, but nonetheless, it's still a really good habit to get into, and if nothing else, I promise, source diving makes you a better developer. So once again, we call the dispatch method, and we've learned that uses the dispatchable trait. Let's dig down. The dispatchable trait, like before, returns a new pending dispatch, and we've now learned

Let's dig down. The Dispatchable trait, like before, returns a new pending dispatch, and we've now learned within the __destruct method is actually where the job is dispatched. So if we drill down to the Dispatcher, and we visit the dispatch method, once again, we return here. However, this time, the command, or the job, in our case, it should be queued, because we checked, does the job implement the ShouldQueue interface? Why, yes! Yes, it does. Okay, let's return.

Routing to Queue Connection1:03

Yes, it does. Okay, let's return. We're back at our dispatch method, and now, we no longer call the dispatchNow method, we instead call dispatchToQueue. Now, here, it starts to get a little more tricky, but not too bad. We begin by checking to see, well, is there a special connection we're using, and in fact, you can set the connection on a per-job basis. So, for example, if I go to ReconcileAccount, and we check out the queueable trait, here's one of the methods you can call on connection. Set the desired connection for the job.

one of the methods you can call on connection. Set the desired connection for the job. And remember, the connection would be things like a database, or SQS, or Redis. Anyways, if we switch back, we haven't set that. So we call the queue resolver, and this is basically going to resolve, well, what queue do you want to use? And you'll remember, in our .env file, we set it to database. So that's going to return to us our database queue. And in fact, you can take a look at that right here. So remember, when we're dealing with a queue, and in fact, let's take a look at the contract

And in fact, you can take a look at that right here. So remember, when we're dealing with a queue, and in fact, let's take a look at the Queue contract here, here's all the various methods you could use. You could push something onto the queue. You could pop one off. You could schedule something for later. Stuff like that. Now, how that takes place will be different, right? If you're using the database connection, obviously, that would involve creating records and removing records and things like that.

If you're using the database connection, obviously, that would involve creating records and removing records and things like that. So for example, if we push, well, for a database queue, we're going to push to the database. For a different queue, like Redis, then when we push, that's going to do it in a different way. Now, we're getting into the weeds a little bit, so let's go on back. But just know at the moment, because we specified the database connection, that's what we're going to use. So continuing on, if the job has a queue method, which means if you want it, you could add a queue method here to declare exactly how this is going to work.

Pushing Job to Queue2:47

So continuing on, if the job has a queue method, which means if you want it, you could add a queue method here to declare exactly how this is going to work. Most of the times, you won't do that, though, and instead, we will call pushCommandToQueue. And the queue is our database queue, and the command is reconcileAccounts. All right, let's dig down further. Push the command onto the given queue instance. Next you'll see three different checks, one, two, and three. So first, if there is a queue instance on the job class itself, and it's delayed, all right, call queue and schedule it for later. Otherwise, if we just have a queue instance, we'll push to it.

right, call queue and schedule it for later. Otherwise, if we just have a queue instance, we'll push to it. If it's just a delayed job, we'll do that. In our case, this is what we're going to be doing. Push the command onto the queue. And don't forget, the queue, in our case, is the database queue. So now we've hit this method. So if we're pushing a new job to the database, let's take a look at that. You'll see we're accepting the payload, and this is something that this class will normalize. And I'll show you that in a minute.

Inserting Database Job Record3:46

You'll see we're accepting the payload, and this is something that this class will normalize. And I'll show you that in a minute. But notice we just get our database adapter, and we're using the default table name. And if I switch over, that will be the jobs table that we set up. And we are inserting a new record into the table where we build the database record. So again, we don't want to get into the weeds too much here, but you can see this is the basic attributes that we will throw into the database. So you'll see here, queue, payload, attempts, reserve that. These records are being populated here. Okay, so now, very quickly, we're starting to see, well, when I call reconcileAccount

These records are being populated here. Okay, so now, very quickly, we're starting to see, well, when I call reconcileAccount dispatch, because we're using the database connection, all we're doing is normalizing the payload and the queue and all the details related to that job, and we are throwing it into the database. And notice this is in stark contrast to the previous episode where we did not queue it. If we remove that contract, the job gets dispatched immediately, and we send it right through the pipeline where the job is executed. But in this example, we're queuing it, which means we're not doing the job right now. We're not doing it as part of this request.

But in this example, we're queuing it, which means we're not doing the job right now. We're not doing it as part of this request. Instead, we are throwing it onto the stack of papers, like we discussed in the first episode. And that stack of papers is this queue here, the default database queue. So now, we're still curious about how we work this job. Well, you'll remember we can run php artisan queue:work. But now, let's figure out what exactly happens when we trigger that command. So I'm just going to try to hunt it down, and I don't know the name of the command, but I can probably find it.

Queue Work Command Flow5:23

So I'm just going to try to hunt it down, and I don't know the name of the command, but I can probably find it. All right, here it is, the work command, and we can confirm this is the command in question. And here are all of the options. Let's take a look at the handle method to figure out what happens. Basically, I want to see when I run php artisan queue work, at some point as part of that command, we literally work on this job until it's complete. OK, let's switch back. First, we check to see, well, if the application is down for maintenance, that's not the case. Here, we're just listening for events to provide some feedback for the user.

First, we check to see, well, if the application is down for maintenance, that's not the case. Here, we're just listening for events to provide some feedback for the user. Next, we figure out what the connection is. So once again, if I go to config/queue.php, it's going to read this setting here. And you'll see in our .env file, our QUEUE_CONNECTION is database, and nothing has changed there. All right, so now the command knows, all right, well, it looks like you have the database connection. So that's what we're going to be working with. So let's go ahead and grab that queue, go to getQueue, and this will return to us the

So that's what we're going to be working with. So let's go ahead and grab that queue, go to getQueue, and this will return to us the queue name. OK, so let's go back, and you'll see, if we dd that, and then run the command, because we didn't specify a specific queue to run in, as always, it will be thrown on the default queue. All right, so now the command has figured out we're using the database connection, and we're using the default queue. So again, I know that can sometimes be confusing. You can have one connection and multiple queues.

So again, I know that can sometimes be confusing. You can have one connection and multiple queues. So if I chose the Redis connection, I could have multiple stacks of paper, and each of those stacks is a queue. I could have my default stack, where most things go. I could have my Fastlane stack. I could have an email stack. I could have some kind of specialty stack. And as we learned, each of those stacks can be referred to as a queue. So that means our database connection, in this case, can have any number of queues.

And as we learned, each of those stacks can be referred to as a queue. So that means our database connection, in this case, can have any number of queues. But in this case, we're throwing it onto the default queue. So now we run the worker that will finally execute and work this job. All right, let's figure out how we run the worker. So we call this method. We accept our database connection, and we accept the default queue. So here, it looks like it delegates to a worker collaborator. And in this case, we're using a daemon. So it's calling this worker daemon while passing through the database connection, the default

And in this case, we're using a daemon. So it's calling this worker daemon while passing through the database connection, the default queue, and any necessary options, which we have not specified any other than the defaults. All right, so let's figure out what is this worker collaborator? Well, if we scroll up, it looks like we have an instance of Illuminate\Queue\Worker, and that's being injected through the constructor. All right, there's our next step. So we know this is calling a daemon method. And if I scroll down, this isn't relevant to us. It'll check.

Worker Fetches and Fires Job8:54

And as we learned, whether it's a Redis connection or a database connection, those adapters, so to speak, will know how to do that. So in our particular case, it runs it through a database transaction. It calls getNextAvailableJob. And here you can see it's a basic SQL query. So using the jobs table, lock it for any updates. And we're going to find a record where the queue is equal to default, where it's available to run, and then finally order it by the ID and give me the first one. So give me the next one that's ready to go. And that's what we return.

It finds the next one that's ready to go. And then it gets processed. And here you can see it's checking to see, well, how many attempts have we run? If it's beyond the maximum number of tries, we need to be aware of that. Otherwise, we will fire the job. So let's see, we should have a DatabaseJob here that we call, that will extend the main Job class. And we call fire. Yeah, there it is. OK, so now I promise we're getting to the end.

Yeah, there it is. OK, so now I promise we're getting to the end. We figure out what the payload is, and that's just going to, we know this is being stored right here. So it's going to json_decode that. All right. Now that we have the payload, we're going to parse the job name based on the payload. So this is how it's figuring out what job are we running? Well, we've now parsed it, and we can see for the job, here's the class we need to resolve, and then there's the method.

Well, we've now parsed it, and we can see for the job, here's the class we need to resolve, and then there's the method. OK, so let's resolve CallQueueHandler. And then we need the call method. And then finally, yeah, we're getting deep in the woods here. But yeah, at this point, you can see we dispatch the job exactly the way we did in the previous episode. But the key thing to understand is, again, at the point this gets called, it's not included as part of that initial request. The initial request where we dispatched the ReconcileAccountJob simply inserted a record.

as part of that initial request. The initial request where we dispatched the reconcileAccount job simply inserted a record into the database and returned very, very fast. But then when we run that php artisan queue:work command, we learned that it uses the database connection in our case to figure out what's the next job you need to do. In that case, it will be this guy here. It then reads the payload. It figures out which class is responsible for calling the job, and then it triggers it. And within there, we call dispatchNow one more time exactly the way we did in the previous.

it. And within there, we call dispatch now one more time exactly the way we did in the previous episode, which means the job gets sent through the pipeline and is completed. So yeah, trust me, I understand we went through a lot of code there. It's fairly complex. In real life, you'd have to spend a good amount of time to fully understand each step of the way because there's so many little things to check for. But mostly, I just wanted you to see that basic flow. What happens when I dispatch a job? Oh, OK, we throw something into the database.

What happens when I dispatch a job? Oh, OK, we throw something into the database. And what happens when we work the job? Well, again, if we're using database, then we reach into the table, we find our next job, we send it through the pipeline, and then we move on to the next job. Now you at least have a basic idea of what's happening there. All right, in the next episode, we're done source diving. We'll move on to something else.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟