Идёт обновление сайта. Несколько дней возможны сбои в оформлении и переводах. Документация работает — если страница выглядит сломанной, обновите её позже.

Документация
L Laravel L intervention/image
Войти
Главная Laravel 10.x Laravel Octane

Laravel Octane

10.x 7 мар 2026 г.

#Введение

Laravel Octane значительно ускоряет работу вашего приложения, используя высокопроизводительные серверы приложений, включая FrankenPHP, Open Swoole, Swoole и RoadRunner. Octane загружает ваше приложение один раз, держит его в памяти и обрабатывает запросы с молниеносной скоростью.

#Установка

Octane можно установить через менеджер пакетов Composer:

composer require laravel/octane

После установки Octane вы можете выполнить Artisan-команду octane:install, которая установит файл конфигурации Octane в ваше приложение:

php artisan octane:install

#Требования к серверу

Внимание

Laravel Octane требует PHP 8.1+.

#FrankenPHP

Внимание

Интеграция FrankenPHP с Octane находится в бета-версии и должна использоваться с осторожностью в продакшене.

FrankenPHP — это сервер приложений PHP, написанный на Go, поддерживающий современные веб-функции, такие как early hints и сжатие Zstandard. При установке Octane и выборе FrankenPHP в качестве сервера Octane автоматически скачает и установит бинарный файл FrankenPHP.

#FrankenPHP через Laravel Sail

Если вы планируете разрабатывать приложение с помощью Laravel Sail, выполните следующие команды для установки Octane и FrankenPHP:

./vendor/bin/sail up

./vendor/bin/sail composer require laravel/octane

Затем используйте Artisan-команду octane:install для установки бинарника FrankenPHP:

./vendor/bin/sail artisan octane:install --server=frankenphp

Наконец, добавьте переменную окружения SUPERVISOR_PHP_COMMAND в определение сервиса laravel.test в файле docker-compose.yml вашего приложения. Эта переменная будет содержать команду, которую Sail будет использовать для запуска вашего приложения через Octane вместо PHP development server:

services:
  laravel.test:
    environment:
      SUPERVISOR_PHP_COMMAND: "/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --server=frankenphp --host=0.0.0.0 --admin-port=2019 --port=80"
      XDG_CONFIG_HOME:  /var/www/html/config
      XDG_DATA_HOME:  /var/www/html/data

Чтобы включить HTTPS, HTTP/2 и HTTP/3, примените следующие изменения:

services:
  laravel.test:
    ports:
        - '${APP_PORT:-80}:80'
        - '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
        - '443:443'
        - '443:443/udp'
    environment:
      SUPERVISOR_PHP_COMMAND: "/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --host=localhost --port=443 --admin-port=2019 --https"
      XDG_CONFIG_HOME:  /var/www/html/config
      XDG_DATA_HOME:  /var/www/html/data

Обычно к вашему приложению FrankenPHP Sail следует обращаться по адресу https://localhost, так как использование https://127.0.0.1 требует дополнительной настройки и не рекомендуется (подробнее).

#FrankenPHP через Docker

Использование официальных Docker-образов FrankenPHP может обеспечить лучшую производительность и поддержку дополнительных расширений, отсутствующих в статических установках FrankenPHP. Кроме того, официальные образы Docker позволяют запускать FrankenPHP на платформах, которые он не поддерживает нативно, например, на Windows. Официальные Docker-образы FrankenPHP подходят как для локальной разработки, так и для продакшена.

Вы можете использовать следующий Dockerfile в качестве отправной точки для контейнеризации вашего Laravel-приложения на базе FrankenPHP:

FROM dunglas/frankenphp

RUN install-php-extensions \
    pcntl
    # Добавьте другие PHP-расширения здесь...

COPY . /app

ENTRYPOINT ["php", "artisan", "octane:frankenphp"]

Затем во время разработки вы можете использовать следующий файл Docker Compose для запуска вашего приложения:

# compose.yaml
services:
  frankenphp:
    build:
      context: .
    entrypoint: php artisan octane:frankenphp --max-requests=1
    ports:
      - "8000:8000"
    volumes:
      - .:/app

Для получения дополнительной информации о запуске FrankenPHP с Docker обратитесь к официальной документации FrankenPHP.

#RoadRunner

RoadRunner работает на бинарном файле RoadRunner, написанном на Go. При первом запуске сервера Octane на базе RoadRunner Octane предложит скачать и установить бинарник RoadRunner.

#RoadRunner через Laravel Sail

Если вы планируете разрабатывать приложение с помощью Laravel Sail, выполните следующие команды для установки Octane и RoadRunner:

./vendor/bin/sail up

./vendor/bin/sail composer require laravel/octane spiral/roadrunner-cli spiral/roadrunner-http 

Затем запустите shell Sail и используйте исполняемый файл rr для загрузки последней версии бинарника RoadRunner для Linux:

./vendor/bin/sail shell

# Внутри shell Sail...
./vendor/bin/rr get-binary

Затем добавьте переменную окружения SUPERVISOR_PHP_COMMAND в определение сервиса laravel.test в файле docker-compose.yml вашего приложения. Эта переменная будет содержать команду, которую Sail будет использовать для запуска вашего приложения через Octane вместо PHP development server:

services:
  laravel.test:
    environment:
      SUPERVISOR_PHP_COMMAND: "/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --server=roadrunner --host=0.0.0.0 --rpc-port=6001 --port=80"

Наконец, убедитесь, что бинарник rr имеет права на выполнение, и соберите образы Sail:

chmod +x ./rr

./vendor/bin/sail build --no-cache

#Swoole

Если вы планируете использовать сервер приложений Swoole для запуска вашего Laravel Octane приложения, необходимо установить PHP-расширение Swoole. Обычно это делается через PECL:

pecl install swoole

#Open Swoole

Если вы хотите использовать сервер приложений Open Swoole для запуска Laravel Octane, необходимо установить PHP-расширение Open Swoole. Обычно это делается через PECL:

pecl install openswoole

Использование Laravel Octane с Open Swoole предоставляет те же возможности, что и Swoole, включая параллельные задачи, тики и интервалы.

#Swoole через Laravel Sail

Внимание

Перед запуском Octane через Sail убедитесь, что у вас установлена последняя версия Laravel Sail и выполните ./vendor/bin/sail build --no-cache в корне вашего приложения.

В качестве альтернативы вы можете разрабатывать Octane-приложение на базе Swoole с помощью Laravel Sail — официальной Docker-среды разработки для Laravel. Laravel Sail включает расширение Swoole по умолчанию, однако вам всё равно потребуется настроить файл docker-compose.yml, используемый Sail.

Для начала добавьте переменную окружения SUPERVISOR_PHP_COMMAND в определение сервиса laravel.test в файле docker-compose.yml вашего приложения. Эта переменная будет содержать команду, которую Sail будет использовать для запуска вашего приложения через Octane вместо PHP development server:

services:
  laravel.test:
    environment:
      SUPERVISOR_PHP_COMMAND: "/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --server=swoole --host=0.0.0.0 --port=80"

Наконец, соберите образы Sail:

./vendor/bin/sail build --no-cache

#Конфигурация Swoole

Swoole поддерживает несколько дополнительных параметров конфигурации, которые вы можете добавить в файл конфигурации octane при необходимости. Поскольку их редко нужно менять, эти параметры не включены в файл конфигурации по умолчанию:

'swoole' => [
    'options' => [
        'log_file' => storage_path('logs/swoole_http.log'),
        'package_max_length' => 10 * 1024 * 1024,
    ],
],

#Запуск приложения

Сервер Octane можно запустить с помощью Artisan-команды octane:start. По умолчанию эта команда использует сервер, указанный в опции server файла конфигурации octane вашего приложения:

php artisan octane:start

По умолчанию Octane запускает сервер на порту 8000, поэтому вы можете открыть приложение в браузере по адресу http://localhost:8000.

#Запуск приложения через HTTPS

По умолчанию приложения, работающие через Octane, генерируют ссылки с префиксом http://. Переменную окружения OCTANE_HTTPS, используемую в файле конфигурации вашего приложения config/octane.php, можно установить в true, если вы обслуживаете приложение по HTTPS. Когда это значение конфигурации установлено в true, Octane укажет Laravel добавлять префикс https:// ко всем генерируемым ссылкам:

'https' => env('OCTANE_HTTPS', false),

#Запуск приложения через Nginx

Примечание

Если вы не готовы самостоятельно настраивать сервер или не уверены в конфигурации всех сервисов для стабильной работы Laravel Octane, ознакомьтесь с Laravel Forge.

В продакшен-средах рекомендуется запускать Octane за традиционным веб-сервером, таким как Nginx или Apache. Это позволит веб-серверу обслуживать статические файлы (изображения, стили) и управлять SSL-сертификатами.

В примере конфигурации Nginx ниже сервер будет обслуживать статические файлы сайта и проксировать запросы к Octane, запущенному на порту 8000:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    listen [::]:80;
    server_name domain.com;
    server_tokens off;
    root /home/forge/domain.com/public;

    index index.php;

    charset utf-8;

    location /index.php {
        try_files /not_exists @octane;
    }

    location / {
        try_files $uri $uri/ @octane;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/domain.com-error.log error;

    error_page 404 /index.php;

    location @octane {
        set $suffix "";

        if ($uri = /index.php) {
            set $suffix ?$query_string;
        }

        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_pass http://127.0.0.1:8000$suffix;
    }
}

#Отслеживание изменений файлов

Поскольку приложение загружается в память один раз при запуске сервера Octane, изменения в файлах приложения не будут отражены при обновлении страницы. Например, добавленные маршруты в routes/web.php не появятся до перезапуска сервера. Для удобства можно использовать флаг --watch, чтобы Octane автоматически перезапускал сервер при изменениях файлов приложения:

php artisan octane:start --watch

Перед использованием этой функции убедитесь, что в вашей локальной среде разработки установлен Node. Также установите библиотеку для отслеживания файлов Chokidar в проект:

npm install --save-dev chokidar

Вы можете настроить директории и файлы для отслеживания через опцию watch в файле конфигурации config/octane.php вашего приложения.

#Указание количества воркеров

По умолчанию Octane запускает по одному воркеру для обработки запросов на каждый CPU-ядро вашей машины. Эти воркеры обрабатывают входящие HTTP-запросы. Вы можете вручную указать количество воркеров с помощью опции --workers при запуске команды octane:start:

php artisan octane:start --workers=4

Если вы используете сервер приложений Swoole, вы также можете указать количество "task workers", которые хотите запустить:

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

#Указание максимального количества запросов

Чтобы предотвратить утечки памяти, Octane плавно перезапускает воркер после обработки 500 запросов. Для изменения этого значения используйте опцию --max-requests:

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

#Перезагрузка воркеров

Вы можете плавно перезапустить воркеры приложения Octane с помощью команды octane:reload. Обычно это делают после деплоя, чтобы загруженный в память код был обновлён и использовался для последующих запросов:

php artisan octane:reload

#Остановка сервера

Остановить сервер Octane можно с помощью Artisan-команды octane:stop:

php artisan octane:stop

#Проверка статуса сервера

Проверить текущий статус сервера Octane можно с помощью Artisan-команды octane:status:

php artisan octane:status

#Внедрение зависимостей и Octane

Поскольку Octane загружает приложение один раз и держит его в памяти при обработке запросов, есть несколько особенностей, которые следует учитывать при разработке. Например, методы register и boot сервис-провайдеров выполняются только один раз при запуске воркера. При последующих запросах используется тот же экземпляр приложения.

В связи с этим следует осторожно внедрять контейнер приложения или запрос в конструкторы объектов. Иначе объект может содержать устаревшую версию контейнера или запроса при последующих запросах.

Octane автоматически сбрасывает внутреннее состояние фреймворка между запросами. Однако Octane не всегда знает, как сбросить глобальное состояние, созданное вашим приложением. Поэтому важно строить приложение с учётом особенностей Octane. Ниже рассмотрены наиболее распространённые ситуации, вызывающие проблемы при использовании Octane.

#Внедрение контейнера

В общем случае следует избегать внедрения контейнера приложения или HTTP-запроса в конструкторы других объектов. Например, следующий биндинг внедряет весь контейнер приложения в объект, зарегистрированный как singleton:

use App\Service;
use Illuminate\Contracts\Foundation\Application;

/**
 * Регистрация сервисов приложения.
 */
public function register(): void
{
    $this->app->singleton(Service::class, function (Application $app) {
        return new Service($app);
    });
}

В этом примере, если экземпляр Service разрешается во время загрузки приложения, контейнер служб будет внедрён в сервис, и тот же контейнер будет храниться в экземпляре Service при последующих запросах. Для вашего приложения это может не быть проблемой; однако это может привести к тому, что в контейнере служб неожиданно будут отсутствовать привязки, добавленные позже в цикле загрузки или в ходе последующего запроса.

В качестве обходного решения можно либо перестать регистрировать биндинг как singleton, либо внедрить в сервис замыкание, которое всегда будет возвращать актуальный экземпляр контейнера:

use App\Service;
use Illuminate\Container\Container;
use Illuminate\Contracts\Foundation\Application;

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

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

Глобальный хелпер app и метод Container::getInstance() всегда возвращают последнюю версию контейнера приложения.

#Внедрение запроса

В общем случае следует избегать внедрения контейнера приложения или HTTP-запроса в конструкторы других объектов. Например, следующий биндинг внедряет весь экземпляр запроса в объект, зарегистрированный как singleton:

use App\Service;
use Illuminate\Contracts\Foundation\Application;

/**
 * Регистрация сервисов приложения.
 */
public function register(): void
{
    $this->app->singleton(Service::class, function (Application $app) {
        return new Service($app['request']);
    });
}

В этом примере если экземпляр Service будет разрешён в процессе загрузки приложения, в сервис будет внедрён HTTP-запрос, и этот же запрос будет храниться в экземпляре Service при последующих запросах. Поэтому все HTTP-заголовки, данные ввода и данные строки запроса будут неверны, как и остальные данные запроса.

В качестве обходного решения можно либо перестать регистрировать биндинг как singleton, либо внедрить в сервис замыкание, которое всегда будет возвращать актуальный экземпляр запроса. Или, что рекомендуется больше всего, просто передавать необходимые данные запроса в методы объекта во время выполнения:

use App\Service;
use Illuminate\Contracts\Foundation\Application;

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

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

// Или...

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

Глобальный хелпер request всегда возвращает текущий обрабатываемый запрос и безопасен для использования в приложении.

Внимание

Допустимо указывать тип Illuminate\Http\Request в методах контроллеров и замыканиях маршрутов.

#Внедрение репозитория конфигурации

В общем случае следует избегать внедрения экземпляра репозитория конфигурации в конструкторы других объектов. Например, следующий биндинг внедряет репозиторий конфигурации в объект, зарегистрированный как singleton:

use App\Service;
use Illuminate\Contracts\Foundation\Application;

/**
 * Регистрация сервисов приложения.
 */
public function register(): void
{
    $this->app->singleton(Service::class, function (Application $app) {
        return new Service($app->make('config'));
    });
}

В этом примере, если значения конфигурации изменятся между запросами, сервис не получит новые значения, так как зависит от исходного экземпляра репозитория.

В качестве обходного решения можно либо перестать регистрировать биндинг как singleton, либо внедрить в класс замыкание, которое всегда возвращает актуальный репозиторий конфигурации:

use App\Service;
use Illuminate\Container\Container;
use Illuminate\Contracts\Foundation\Application;

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

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

Глобальный хелпер config всегда возвращает последнюю версию репозитория конфигурации и безопасен для использования в приложении.

#Управление утечками памяти

Помните, что Octane держит приложение в памяти между запросами; поэтому добавление данных в статический массив приведёт к утечке памяти. Например, следующий контроллер содержит утечку памяти, так как каждый запрос добавляет данные в статический массив $data:

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

/**
 * Обработка входящего запроса.
 */
public function index(Request $request): array
{
    Service::$data[] = Str::random(10);

    return [
        // ...
    ];
}

При разработке приложения следует внимательно избегать подобных утечек памяти. Рекомендуется мониторить использование памяти приложения в локальной среде, чтобы не допускать новых утечек.

#Параллельные задачи

Внимание

Эта функция требует Swoole.

При использовании Swoole вы можете выполнять операции параллельно с помощью лёгких фоновых задач. Это можно сделать с помощью метода concurrently Octane. Результаты каждой операции можно получить, используя деструктуризацию массива PHP:

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

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

Параллельные задачи в Octane обрабатываются с помощью "task workers" Swoole и выполняются в отдельном процессе, отличном от процесса входящего запроса. Количество воркеров для обработки параллельных задач задаётся директивой --task-workers команды octane:start:

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

При вызове метода concurrently не следует передавать более 1024 задач из-за ограничений системы задач Swoole.

#Тики и интервалы

Внимание

Эта функция требует Swoole.

При использовании Swoole вы можете регистрировать операции "тик", которые будут выполняться через заданный интервал секунд. Для этого используйте метод tick. Первый аргумент метода tick — строка с именем тикера, второй — вызываемый callback, который будет выполняться через указанный интервал.

В этом примере мы регистрируем замыкание, вызываемое каждые 10 секунд. Обычно метод tick вызывается в методе boot одного из сервис-провайдеров приложения:

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

С помощью метода immediate можно заставить Octane сразу вызвать callback тика при запуске сервера Octane и затем каждые N секунд:

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

#Кэш Octane

Внимание

Эта функция требует Swoole.

При использовании Swoole вы можете использовать драйвер кэша Octane, обеспечивающий скорость чтения и записи до 2 миллионов операций в секунду. Этот драйвер отлично подходит для приложений, которым нужна экстремальная скорость работы с кэшем.

Этот драйвер основан на таблицах Swoole. Все данные кэша доступны всем воркерам сервера. Однако данные кэша будут сброшены при перезапуске сервера:

Cache::store('octane')->put('framework', 'Laravel', 30);
Примечание

Максимальное количество записей в кэше Octane можно задать в файле конфигурации octane вашего приложения.

#Интервалы кэша

Помимо стандартных методов Laravel Cache, драйвер кэша Octane поддерживает кэши с обновлением по интервалу. Такие кэши автоматически обновляются через заданный интервал и должны регистрироваться в методе boot одного из сервис-провайдеров приложения. Например, следующий кэш обновляется каждые пять секунд:

use Illuminate\Support\Str;

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

#Таблицы

Внимание

Эта функция требует Swoole.

При использовании Swoole вы можете создавать и работать с произвольными таблицами Swoole. Таблицы Swoole обеспечивают высокую производительность, а данные в них доступны всем воркерам сервера. Однако данные теряются при перезапуске сервера.

Таблицы следует определять в массиве конфигурации tables файла octane вашего приложения. Пример таблицы с максимальным количеством 1000 строк уже настроен для вас. Максимальный размер строковых колонок можно задать, указав размер после типа колонки, как показано ниже:

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

Для доступа к таблице используйте метод Octane::table:

use Laravel\Octane\Facades\Octane;

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

return Octane::table('example')->get('uuid');
Внимание

Поддерживаемые типы колонок в таблицах Swoole: string, int и float.