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

Concurrent Tasks Overview0:00

In a previous lesson, we mentioned that using the Swoole Octane driver gives us extra features that aren't available when using the Roadrunner driver. One of these features is the ability to run tasks in the background and wait for the results. This allows us to run tasks concurrently, collect the results, and use them in our request handling code. It is very similar to the Laravel queue workers, however, the difference is that you can wait for the tasks to complete and collect the output. So for example, you can execute multiple slow API requests concurrently and collect the response and use it while handling a single request. You can also use it to run multiple slow SQL queries concurrently and use the results in

Configuring Task Workers0:42

response and use it while handling a single request. You can also use it to run multiple slow SQL queries concurrently and use the results in your controller. This gives your application a speed boost by utilizing available server resources to execute input-output operations concurrently. Now, in order to achieve this, we need to start a number of task workers while starting the Octane server. Let's see how we can do that. When we look at the Octane start command, we can see the workers option. This one determines the number of web workers we want Octane to start.

When we look at the octane:start command, we can see the --workers option. This one determines the number of web workers we want Octane to start. These workers handle web requests. And by default, the value is set to auto, which means Octane will start a number of workers that's equal to the number of CPU cores your machine has. There is another option called --task-workers. These workers handle concurrent tasks that we want to run. It's set to auto by default as well. So Octane starts a number of task workers that's equal to the number of CPU cores the machine has.

Baseline Slow Query Test1:52

So Octane starts a number of task workers that's equal to the number of CPU cores the machine has. Let's see how we can utilize these task workers. In my web.php routes file, I have a route that records the start time of the request, It runs a SQL query that just sleeps for 2 seconds to simulate a slow query. And it also runs another SQL query that sleeps for 2 seconds. And finally returns the time difference between the current time and the request start time. Let's start the Octane server and see what we get. Now we visit the browser and send a request. And here we go, the result is 4 seconds.

Running Tasks Concurrently2:38

Now we visit the browser and send a request. And here we go, the result is 4 seconds. That's because the two queries ran in sequence, one after the other. So the total of their execution time is 4 seconds. Let's see how we may run them concurrently. We will use the Octane facade and call a concurrently method. This method accepts an array of tasks to run concurrently. For the first task, we will put a closure and move the SQL statement inside the closure. And then we return 1 as an output for this closure. In a real-life scenario, you would want to return the result of the SQL query instead.

And then we return 1 as an output for this closure. In a real-life scenario, you would want to return the result of the SQL query instead. Now let's copy this and paste it as the second task to run. Change the output of 2 instead of 1. And then remove the old query statement. Now let's assign the result of these two tasks to some variables. So here I will assign the result of the first task to a variable named result1. And that of the second task to result2. Then in the response, we return these variables, result1 and result2. Now let's restart the Octane server by stopping it and starting it again.

Then in the response, we return these variables, result1 and result2. Now let's restart the Octane server by stopping it and starting it again. Then we head to the browser and refresh. Wait for a few seconds. And here we go. The response time is now 2 seconds instead of 4 seconds. That's because Octane sent the two tasks to two task workers to run concurrently, collected the results and sent it back to us. Which allowed us to cut 50% of the request execution time. Now you should know that these two tasks ran on two different database connections.

Database Connection Considerations4:48

Which allowed us to cut 50% of the request execution time. Now you should know that these two tasks ran on two different database connections. Which means that by utilizing Octane tasks, you need to make sure that the database is powerful enough to handle connections from web workers, task workers, and queue workers as well. Each of these workers require a dedicated database connection to run queries. So if you have, let's say 20 web workers, 20 task workers, and 20 queue workers, you will need to have a database that can handle 60 open connections. Now let's take a look at another cool feature that Octane with Swoole offers, which is the ability to register timers that invoke a certain function on a regular basis.

Scheduling Timers with Tick5:31

Now let's take a look at another cool feature that Octane with Swoole offers, which is the ability to register timers that invoke a certain function on a regular basis. This is similar to the Laravel scheduler, except that you can schedule commands that will be executed every specified number of seconds instead of minutes. Let's see how we can achieve this. Inside the AppServiceProvider, we will go to the put method and then use the Octane facade to call the tick method. This method accepts two arguments. The first one is the name of the ticker or the timer. We will call this timer logger as our timer will just log a string every couple of seconds.

The first one is the name of the ticker or the timer. We will call this timerLogger as our timer will just log a string every couple of seconds. And for the second argument, we will define a closure. And inside the closure, we will use the info helper function to log a tick string. Now we will call the seconds method to set the interval for our timer. We will set it to 2 seconds. Let's then start the Octane server. Then we go to the logs file. And here we go. The first tick came at the first second of the 35th minute.

And here we go. The first tick came at the first second of the 35th minute. We can see two log entries here due to a bug in Octane. But if we wait a bit, reload the file, we can see that the ticks are coming every 2 seconds as expected. So only the first tick is executed twice. We may also instruct Octane to immediately invoke the tick callback when the Octane server starts, and then every 2 seconds after that. And to do that, we use the immediate method. This can come in handy if you want to clear the state at the server initialization stage.

And to do that, we use the immediate method. This can come in handy if you want to clear the state at the server initialization stage. Like if you use the timers to clear the cache every 10 seconds, and you want to ensure the cache is clear from the start. Or you are implementing a health check heartbeat that runs every 30 seconds. You send the first heartbeat to indicate the server started, and then every 30 seconds to indicate the server is still running. For the first use case, there is another way to use Octane ticks to clear a cache. This feature is also powered by Swoole, and a specific functionality in Swoole called Swoole tables, which provides a cache driver with read and write capabilities and speeds up

Using Swoole Table Cache8:14

This feature is also powered by Swoole, and a specific functionality in Swoole called SwooleTables, which provides a cache driver with read and write capabilities and speeds up to 2 million operations per second, which makes it an excellent choice for applications that need extreme read and write speeds from the caching layer. It's even better than Redis. Let's see how we may use it. Inside our route here, we will use the Cache facade, with the Octane cache store, and call the remember method. This method accepts the cache key at the first parameter, let's call it time, the cache interval as the second parameter, let's use 5, and then a closure.

This method accepts the cache key at the first parameter, let's call it time, the cache interval as the second parameter, let's use 5, and then a closure. Inside the closure, we will return the current microtime. Now as a response, let's return the value of the time cache key using the get method. Let's start the Octane server, visit the browser, and refresh, and here we can see the current time stored in the cache. If we refresh several times, we get the same value, because the value is cached. But if we wait for 5 seconds, and then refresh, we see a different value. That's because the Octane cache invalidates the cache every 5 seconds and stores a new value.

That's because the Octane cache invalidates the cache every 5 seconds and stores a new value. That means you can already achieve this using existing Laravel cache drivers, but the Octane cache is faster than even the Redis driver. So you may use it to add a performance boost to your application. And as I mentioned, this cache driver uses Swoole tapers under the hood to store the values, so make sure you are using the Swoole Octane driver to be able to use this feature. Because the shared memory mode, concurrent tasks, ticks, and a super fast cache layer, Octane gives your Laravel application superpowers that weren't available before. And with great power comes great responsibility.

Octane gives your Laravel application superpowers that weren't available before. And with great power comes great responsibility. Make sure to check the guidelines we shared in the previous lessons to know how to responsibly use Octane in your Laravel application. That's it for this lesson, and I will see you in the next one.

Concurrent TasksPeriodic TasksIn-memory Cache

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