Introduction to the

Laravel Octane enhanced the performance of the application by using a powerful application server, Swoole and Roadrunner, to serve the application. Octane boots your application once, saves it in memory, and then serves the request at supersonic speeds.

The official address

The installation

Octane can be installed through the Composer package manager:


composer require laravel/octane

After you install Octane, you can execute the Octane: Install Artisan command, which will install Octane’s configuration file into your application:

php artisan octane:install

The installation conditions

  • PHP8+
  • Laravel v. 8.37 +

RoadRunner

ROADRUNNER is powered by a ROADRUNNER binary built using GO. When you first start the Roadrunner based Octane server, Octane will download and install the Roadrunner binaries for you.

RoadRunner Via Laravel Sail

Roadrunner specific use can be viewed in the original article.

Swoole installation

pecl install swoole

Start your service

Can be achieved by
octane:startArtisanCommand to start the
OctaneThe server. By default, this command will utilize
serverThe application
octaneConfiguration file configuration options for specified server:

php artisan octane:start

Set to apply HTTPS. Configure

OCTANE_HTTPS=false

Set up the container to start the service

OCTANE_SERVER=swoole

Application code is hot loaded

php artisan octane:start --watch
  • Note that you should ensure that the Node service is installed locally before using this command. You should install the Chokidar file monitoring library in your project: Library:
npm install --save-dev chokidar

You can use the configuration options in the config/octane.php configuration file of the Watch application to configure the directories and files that should be monitored.

Specifies the number of worker processes

By default, Octane will start an application request worker for each CPU core provided by your computer. These workers will then be used to process incoming HTTP requests when they come into your application. You can manually specify the number of workers to use this option when the –workers call the octane:start command:

php artisan octane:start --workers=4

If you are using a Swoole application server, you can also specify the number of “task workers” to start:

php artisan octane:start --workers=4 --task-workers=6

Specifies the maximum number of requests

php artisan octane:start --max-requests=250

Service to restart

You can use the following
octane:reloadCommand to restart the Octane server’s application worker normally. In general, this should be done after deployment so that the newly deployed code can be loaded into memory and used to handle subsequent requests:

php artisan octane:reload

Service is down

You can use the Octane: StopArtisan command to stop the Octane server:

php artisan octane:stop

View service status

php artisan octane:status

Octane Dependency Injection

Because Octane boots your application at a time and keeps it in memory while the request is processed, there are a few considerations you should keep in mind when building your application. For example, your application service provider’s registerand boot methods are executed only once when the request initiator is initially started. The same application instance will be reused in subsequent requests.

With this in mind, care should be taken when injecting an application service container or request into the constructor of any object. Thus, the object may have an older version of the container or a request in a subsequent request.

Octane will automatically handle reset requests between any of the first party frame states. However, Octane does not always know how to reset the global state created by the application. Therefore, you should know how to build your application in an Octane-friendly way. Below, we’ll discuss the most common situations where octane numbers can cause problems.

Container injection

In general, you should avoid injecting application service containers or HTTP request instances into the constructors of other objects. For example, the following binding injects the entire application service container into an object as a singleton binding:

use App\Service;

/**
 * Register any application services.
 *
 * @return void
 */
public function register()
{
    $this->app->singleton(Service::class, function ($app) {
        return new Service($app);
    });
}

In this example, if the Service resolves the instance during application startup, the container will be injected into the Service and the Service instance will retain the container for subsequent requests. For your particular application, this may not be an issue; However, this can cause the container to accidentally lose bindings that were added late in the boot cycle or in subsequent requests.

The solution is that you can either stop registering bindings as singletons, or you can inject container parser closures into services that always resolve the current container instance: </p>

use App\Service;
use Illuminate\Container\Container;

$this->app->bind(Service::class, function ($app) {
    return new Service($app);
});

$this->app->singleton(Service::class, function () {
    return new Service(fn () => Container::getInstance());
});

The global app helper and the Container::getInstance() method will always return the latest version of the application Container.

Request to inject

In general, you should avoid injecting application service containers or HTTP request instances into the constructors of other objects. For example, the following binding injects the entire request instance into an object that is bound as a singleton:

use App\Service;

/**
 * Register any application services.
 *
 * @return void
 */
public function register()
{
    $this->app->singleton(Service::class, function ($app) {
        return new Service($app['request']);
    });
}

In this example, if the Service resolves the instance during application startup, the HTTP request will be injected into the Service and the Service instance will retain the same request in subsequent requests. Therefore, all header, input and query string data, and all other request data will be incorrect.

The solution is that you can stop registering bindings as singletons, or you can inject the request resolver closure into a service that always resolves the current request instance. Or, the most recommended method is simply one of the ways to pass the specific request information that the object needs to the object at run time:

use App\Service;

$this->app->bind(Service::class, function ($app) {
    return new Service($app['request']);
});

$this->app->singleton(Service::class, function ($app) {
    return new Service(fn () => $app['request']);
});

// Or...

$service->method($request->input('name'));

The global Request helper will always return the request that the application is currently processing, so it can be used safely in your application.

Configuration file injection

In general, you should avoid injecting configuration instances into constructors of other objects. For example, the following bindings inject configuration into an object that is a singleton binding:

use App\Service;

/**
 * Register any application services.
 *
 * @return void
 */
public function register()
{
    $this->app->singleton(Service::class, function ($app) {
        return new Service($app->make('config'));
    });
}

In this example, if the configuration value changes between requests, the service will not be able to access the new value because it depends on the original repository instance.

The solution is that you can either stop registering bindings as singletons, or you can inject the configuration repository parser closure into the class:

use App\Service;
use Illuminate\Container\Container;

$this->app->bind(Service::class, function ($app) {
    return new Service($app->make('config'));
});

$this->app->singleton(Service::class, function () {
    return new Service(fn () => Container::getInstance()->make('config'));
});

Global Config will always return the most recent version of the configuration, so it can be used safely in your application.

Managing memory leaks

Remember that Octane keeps your application in memory between requests; Therefore, adding data to a statically maintained array will result in a memory leak. For example, because each request to the application’s > order will continue to add data to the static $data array, the following controller has a memory leak:

se App\Service;
use Illuminate\Http\Request;
use Illuminate\Support\Str;

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return void
 */
public function index(Request $request)
{
    Service::$data[] = Str::random(10);

    // ...
}

Concurrent tasks

  • Indicates that this function requires a Swoole

When you use Swoole, you can perform operations simultaneously through lightweight background tasks. You can concurrently complete this operation using Octane:: Tick concurrently. You can combine this method with the PHP array decompose > construct to retrieve the result of each operation:


use App\User;
use App\Server;
use Laravel\Octane\Facades\Octane;

[$users, $servers] = Octane::concurrently([
    fn () => User::all(),
    fn () => Server::all(),
]);

Concurrent tasks handled by Octane take advantage of Swoole’s “task workers” and execute in a completely different process from the incoming request. The number of workers available to process concurrent tasks is
--task-workersOn the command
octane:startDirective determination:

php artisan octane:start --workers=4 --task-workers=6

Timer & time interval

  • Indicates that this function requires a Swoole

When you use Swoole, you can register the “tick” operation that will be executed every specified number of seconds. You can register a “tick” callback through the tick method. The first argument to the tick method should be a string representing the name of the stock ticker indicator. The second argument should be callable, and it will be called at a specified interval.

In this example, we will register a closure that will be invoked every 10 seconds. Typically, Tick should call this method inside a method of one of the Boot application’s service providers:

Octane::tick('simple-ticker', fn () => ray('Ticking... ')) ->seconds(10);

The use of the
immediateMethod, you can instruct Octane to call the Tick callback immediately after the Octane server is initially started, and every N seconds thereafter:

Octane::tick('simple-ticker', fn () => ray('Ticking... ')) ->seconds(10) ->immediate();

Octane cache

This function relies on [Swoole]()

With Swoole, you can take advantage of the Octane cache driver, which provides read and write speeds of up to 2 million operations per second. Therefore, this cache driver is an excellent choice for applications that need to achieve extremely high read/write speeds from their cache layer. The cache driver is powered by the Swoole table. All data stored in the cache is available to all workers on the server. However, after restarting the server, the cached data will be flushed:

Cache::store('octane')->put('framework', 'Laravel', 30);

Cache spacing

In addition to the typical methods provided by the Laravel caching system, the Octane cache driver also has space-based caching. These caches will be flushed automatically at specified intervals and should be registered using the Boot method of one of your application’s service providers. For example, the following cache will be refreshed every five seconds:

use Illuminate\Support\Str;

Cache::store('octane')->interval('random', function () {
    return Str::random(10);
}, seconds: 5)

Shared memory between processes (table)

When you use Swoole, you can define and interact with any of your own Swoole tables. Swoole tables provide extremely high performance throughput, and the data in these tables is accessible to all workers on the server. However, when the server is restarted, the data in it will be lost.

Tables should be defined in the configuration array of the Tables application’s Octane configuration file. A sample table has been configured for you that allows up to 1000 rows. The maximum size of a string column can be configured by specifying the column size after the column type, as follows:

'tables' => [
    'example:1000' => [
        'name' => 'string:1000',
        'votes' => 'int',
    ],
],

To access a table, use the following Octane:: Table method:


use Laravel\Octane\Facades\Octane;

Octane::table('example')->set('uuid', [
    'name' => 'Nuno Maduro',
    'votes' => 1000,
]);

return Octane::table('example')->get('uuid');

The column types supported through the Swoole table: String, int, and float.

Address translation