Documentación de Laravel 10.x
Aquí encontrarás fragmentos de código de Laravel y consejos útiles sobre desarrollo web.
Laravel Octane potencia el rendimiento de tu aplicación al servirla utilizando servidores de aplicaciones potentes, incluidos Open Swoole, Swoole y RoadRunner. Octane inicia tu aplicación una vez, la mantiene en memoria y luego le envía solicitudes a velocidades supersónicas.
Octane se puede instalar a través del administrador de paquetes Composer:
composer require laravel/octane
Después de instalar Octane, puedes ejecutar el comando Artisan octane:install
, que instalará el archivo de configuración de Octane en tu aplicación:
php artisan octane:install
Advertencia Laravel Octane requiere PHP 8.1+.
RoadRunner está alimentado por el binario RoadRunner, que está construido con Go. La primera vez que inicias un servidor Octane basado en RoadRunner, Octane te ofrecerá descargar e instalar el binario RoadRunner por ti.
Si planeas desarrollar tu aplicación utilizando Laravel Sail, debes ejecutar los siguientes comandos para instalar Octane y RoadRunner:
./vendor/bin/sail up ./vendor/bin/sail composer require laravel/octane spiral/roadrunner-cli spiral/roadrunner-http
A continuación, debes iniciar un shell de Sail y utilizar el ejecutable rr
para obtener la última versión del binario RoadRunner basado en Linux:
./vendor/bin/sail shell # Within the Sail shell..../vendor/bin/rr get-binary
Después de instalar el binario RoadRunner, puedes salir de tu sesión de shell de Sail. Ahora deberás ajustar el archivo supervisor.conf
utilizado por Sail para mantener tu aplicación en funcionamiento. Para empezar, ejecuta el comando Artisan sail:publish
:
./vendor/bin/sail artisan sail:publish
A continuación, actualiza la directiva command
del archivo docker/supervisord.conf
de tu aplicación para que Sail sirva tu aplicación utilizando Octane en lugar del servidor de desarrollo 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
Finalmente, asegúrate de que el binario rr
sea ejecutable y construye las imágenes de Sail:
chmod +x ./rr ./vendor/bin/sail build --no-cache
Si planeas utilizar el servidor de aplicaciones Swoole para servir tu aplicación Laravel Octane, debes instalar la extensión de PHP Swoole. Por lo general, esto se puede hacer a través de PECL:
pecl install swoole
Si deseas utilizar el servidor de aplicaciones Open Swoole para servir tu aplicación Laravel Octane, debes instalar la extensión de PHP Open Swoole. Por lo general, esto se puede hacer a través de PECL:
pecl install openswoole
El uso de Laravel Octane con Open Swoole proporciona la misma funcionalidad que Swoole, como tareas concurrentes, ticks e intervalos.
Advertencia Antes de servir una aplicación Octane a través de Sail, asegúrate de tener la última versión de Laravel Sail y ejecuta
./vendor/bin/sail build --no-cache
dentro del directorio raíz de tu aplicación.
Alternativamente, puedes desarrollar tu aplicación Octane basada en Swoole utilizando Laravel Sail, el entorno de desarrollo oficial basado en Docker para Laravel. Laravel Sail incluye la extensión Swoole por defecto. Sin embargo, aún deberás ajustar el archivo supervisor.conf
utilizado por Sail para mantener en ejecución tu aplicación. Para empezar, ejecuta el comando Artisan sail:publish
:
./vendor/bin/sail artisan sail:publish
A continuación, actualiza la directiva command
en el archivo docker/supervisord.conf
de tu aplicación para que Sail sirva tu aplicación utilizando Octane en lugar del servidor de desarrollo de PHP:
command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --server=swoole --host=0.0.0.0 --port=80
Finalmente, construye tus imágenes de Sail:
./vendor/bin/sail build --no-cache
Swoole admite algunas opciones de configuración adicionales que puedes agregar a tu archivo de configuración octane
si es necesario. Dado que rara vez es necesario modificarlas, estas opciones no se incluyen en el archivo de configuración predeterminado:
'swoole' => [ 'options' => [ 'log_file' => storage_path('logs/swoole_http.log'), 'package_max_length' => 10 * 1024 * 1024, ],],
El servidor Octane se puede iniciar mediante el comando Artisan octane:start
. Por defecto, este comando utilizará el servidor especificado por la opción de configuración server
en el archivo octane
de tu aplicación:
php artisan octane:start
Por defecto, Octane iniciará el servidor en el puerto 8000, por lo que podrás acceder a tu aplicación en un navegador web a través de http://localhost:8000
.
Por defecto, las aplicaciones que se ejecutan a través de Octane generan enlaces con el prefijo http://
. La variable de entorno OCTANE_HTTPS
, utilizada en el archivo de configuración config/octane.php
de tu aplicación, puede establecerse en true
cuando sirvas tu aplicación a través de HTTPS. Cuando este valor de configuración se establece en true
, Octane indicará a Laravel que prefije todos los enlaces generados con https://
:
'https' => env('OCTANE_HTTPS', false),
Nota Si aún no estás listo para gestionar la configuración de tu propio servidor o no te sientes cómodo configurando todos los diversos servicios necesarios para ejecutar una aplicación robusta de Laravel Octane, consulta Laravel Forge.
En entornos de producción, debes servir tu aplicación Octane detrás de un servidor web tradicional como Nginx o Apache. De esta manera, el servidor web podrá servir tus activos estáticos, como imágenes y hojas de estilo, además de gestionar la terminación del certificado SSL.
En el ejemplo de configuración de Nginx a continuación, Nginx servirá los activos estáticos del sitio y dirigirá las solicitudes al servidor Octane que se ejecuta en el puerto 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; }}
Dado que tu aplicación se carga en memoria una vez cuando se inicia el servidor Octane, cualquier cambio en los archivos de tu aplicación no se reflejará al actualizar el navegador. Por ejemplo, las definiciones de ruta agregadas a tu archivo routes/web.php
no se reflejarán hasta que se reinicie el servidor. Para mayor comodidad, puedes utilizar la bandera --watch
para indicarle a Octane que reinicie automáticamente el servidor ante cualquier cambio de archivos en tu aplicación:
php artisan octane:start --watch
Antes de utilizar esta función, asegúrate de que Node esté instalado en tu entorno de desarrollo local. Además, debes instalar la biblioteca de observación de archivos Chokidar en tu proyecto:
npm install --save-dev chokidar
Puedes configurar los directorios y archivos que se deben observar mediante la opción de configuración watch
en el archivo de configuración config/octane.php
de tu aplicación.
Por defecto, Octane iniciará un trabajador de solicitud de aplicación por cada núcleo de CPU proporcionado por tu máquina. Estos trabajadores se utilizarán para atender las solicitudes HTTP entrantes a medida que ingresan a tu aplicación. Puedes especificar manualmente cuántos trabajadores deseas iniciar utilizando la opción --workers
al invocar el comando octane:start
:
php artisan octane:start --workers=4
Si estás utilizando el servidor de aplicaciones Swoole, también puedes especificar cuántos "trabajadores de tareas" deseas iniciar:
php artisan octane:start --workers=4 --task-workers=6
Para ayudar a prevenir posibles fugas de memoria, Octane reinicia graciosamente cualquier trabajador una vez que ha manejado 500 solicitudes. Para ajustar este número, puedes utilizar la opción --max-requests
:
php artisan octane:start --max-requests=250
Puedes reiniciar graciosamente los trabajadores de aplicación del servidor Octane utilizando el comando octane:reload
. Normalmente, esto se debe hacer después de implementar para que tu código recién implementado se cargue en memoria y se utilice para atender las solicitudes posteriores:
php artisan octane:reload
Puedes detener el servidor Octane utilizando el comando Artisan octane:stop
:
php artisan octane:stop
Puedes verificar el estado actual del servidor Octane utilizando el comando Artisan octane:status
:
php artisan octane:status
Dado que Octane inicia tu aplicación una vez y la mantiene en memoria mientras atiende solicitudes, hay algunas advertencias que debes tener en cuenta al construir tu aplicación. Por ejemplo, los métodos register
y boot
de los proveedores de servicios de tu aplicación solo se ejecutarán una vez cuando el trabajador de solicitudes se inicie inicialmente. En solicitudes subsiguientes, se reutilizará la misma instancia de aplicación.
En este sentido, debes tener cuidado al inyectar el contenedor de servicios de la aplicación o la solicitud en el constructor de cualquier objeto. Al hacerlo, ese objeto puede tener una versión obsoleta del contenedor o de la solicitud en solicitudes subsiguientes.
Octane manejará automáticamente la restauración de cualquier estado del framework de primera parte entre solicitudes. Sin embargo, Octane no siempre sabe cómo restablecer el estado global creado por tu aplicación. Por lo tanto, debes ser consciente de cómo construir tu aplicación de una manera que sea amigable con Octane. A continuación, discutiremos las situaciones más comunes que pueden causar problemas al usar Octane.
En general, debes evitar inyectar el contenedor de servicios de la aplicación o la instancia de solicitud HTTP en los constructores de otros objetos. Por ejemplo, la siguiente vinculación inyecta el contenedor de servicios completo en un objeto que se vincula como un singleton:
use App\Service;use Illuminate\Contracts\Foundation\Application; /** * Registrar cualquier servicio de la aplicación. */public function register(): void{ $this->app->singleton(Service::class, function (Application $app) { return new Service($app); });}
En este ejemplo, si la instancia de Service
se resuelve durante el proceso de inicio de la aplicación, el contenedor se inyectará en el servicio y esa misma instancia del contenedor se mantendrá en la instancia de Service
en solicitudes subsiguientes. Esto puede no ser un problema para tu aplicación en particular; sin embargo, puede llevar a que el contenedor no tenga inyecciones que se agregaron más adelante en el ciclo de inicio o por una solicitud subsiguiente.
Como solución temporal, podrías dejar de registrar la vinculación como un singleton o podrías inyectar un cierre de resolución del contenedor en el servicio que siempre resuelva la instancia actual del contenedor:
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());});
El ayudante global app
y el método Container::getInstance()
siempre devolverán la versión más reciente del contenedor de la aplicación.
En general, debes evitar inyectar el contenedor de servicios de la aplicación o la instancia de solicitud HTTP en los constructores de otros objetos. Por ejemplo, la siguiente vinculación inyecta la instancia completa de la solicitud en un objeto que se vincula como un singleton:
use App\Service;use Illuminate\Contracts\Foundation\Application; /** * Registrar cualquier servicio de la aplicación. */public function register(): void{ $this->app->singleton(Service::class, function (Application $app) { return new Service($app['request']); });}
En este ejemplo, si la instancia de Service
se resuelve durante el proceso de inicio de la aplicación, la solicitud HTTP se inyectará en el servicio y esa misma solicitud se mantendrá en la instancia de Service
en solicitudes subsiguientes. Por lo tanto, todas las cabeceras, datos de entrada y cadena de consulta serán incorrectos, así como todos los demás datos de la solicitud.
Como solución temporal, podrías dejar de registrar la vinculación como un singleton, o podrías inyectar un cierre de resolución de solicitud en el servicio que siempre resuelva la instancia actual de la solicitud. O, el enfoque más recomendado es simplemente pasar la información específica de la solicitud que tu objeto necesita a uno de los métodos del objeto en tiempo de ejecución:
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']);}); // Or... $service->method($request->input('name'));
El ayudante global request
siempre devolverá la solicitud que la aplicación está manejando actualmente y, por lo tanto, es seguro usarlo dentro de tu aplicación.
Advertencia Es aceptable hacer una sugerencia de tipo de instancia
Illuminate\Http\Request
en los métodos de controlador y cierres de rutas.
En general, debes evitar inyectar la instancia del repositorio de configuración en los constructores de otros objetos. Por ejemplo, la siguiente vinculación inyecta el repositorio de configuración en un objeto que se vincula como un singleton:
use App\Service;use Illuminate\Contracts\Foundation\Application; /** * Registrar cualquier servicio de la aplicación. */public function register(): void{ $this->app->singleton(Service::class, function (Application $app) { return new Service($app->make('config')); });}
En este ejemplo, si los valores de configuración cambian entre solicitudes, ese servicio no tendrá acceso a los nuevos valores porque depende de la instancia original del repositorio.
Como solución temporal, podrías dejar de registrar la vinculación como un singleton, o podrías inyectar un cierre de resolución de repositorio de configuración en la clase:
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'));});
El global config
siempre devolverá la última versión del repositorio de configuración y, por lo tanto, es seguro usarlo dentro de tu aplicación.
Recuerda, Octane mantiene tu aplicación en memoria entre solicitudes; por lo tanto, agregar datos a una matriz mantenida estáticamente resultará en una fuga de memoria. Por ejemplo, el siguiente controlador tiene una fuga de memoria ya que cada solicitud a la aplicación seguirá agregando datos a la matriz estática $data
:
use App\Service;use Illuminate\Http\Request;use Illuminate\Support\Str; /** * Manejar una solicitud entrante. */public function index(Request $request): array{ Service::$data[] = Str::random(10); return [ // ... ];}
Al construir tu aplicación, debes tener especial cuidado para evitar la creación de estos tipos de fugas de memoria. Se recomienda que supervises el uso de memoria de tu aplicación durante el desarrollo local para asegurarte de que no estás introduciendo nuevas fugas de memoria en tu aplicación.
Advertencia Esta característica requiere Swoole.
Al usar Swoole, puedes ejecutar operaciones de forma concurrente a través de tareas de fondo livianas. Puedes lograr esto utilizando el método concurrently
de Octane. Puedes combinar este método con la destrucción de matrices de PHP para recuperar los resultados de cada operación:
use App\Models\User;use App\Models\Server;use Laravel\Octane\Facades\Octane; [$users, $servers] = Octane::concurrently([ fn () => User::all(), fn () => Server::all(),]);
Las tareas concurrentes procesadas por Octane utilizan los "trabajadores de tareas" de Swoole y se ejecutan en un proceso completamente diferente al de la solicitud entrante. La cantidad de trabajadores disponibles para procesar tareas concurrentes se determina por la directiva --task-workers
en el comando octane:start
:
php artisan octane:start --workers=4 --task-workers=6
Al invocar el método concurrently
, no debes proporcionar más de 1024 tareas debido a las limitaciones impuestas por el sistema de tareas de Swoole.
Advertencia Esta característica requiere Swoole.
Al usar Swoole, puedes registrar operaciones "tick" que se ejecutarán cada número especificado de segundos. Puedes registrar devoluciones de llamada "tick" mediante el método tick
. El primer argumento proporcionado al método tick
debe ser una cadena que represente el nombre del temporizador. El segundo argumento debe ser un callable que se invocará en el intervalo especificado.
En este ejemplo, registraremos un cierre que se invocará cada 10 segundos. Normalmente, el método tick
debería llamarse dentro del método boot
de uno de los proveedores de servicios de tu aplicación:
Octane::tick('simple-ticker', fn () => ray('Ticking...')) ->seconds(10);
Usando el método immediate
, puedes indicar a Octane que invoque inmediatamente la devolución de llamada de tick cuando el servidor Octane se inicie inicialmente y cada N segundos después:
Octane::tick('simple-ticker', fn () => ray('Ticking...')) ->seconds(10) ->immediate();
Advertencia Esta característica requiere Swoole.
Al usar Swoole, puedes aprovechar el controlador de caché de Octane, que proporciona velocidades de lectura y escritura de hasta 2 millones de operaciones por segundo. Por lo tanto, este controlador de caché es una excelente opción para aplicaciones que necesitan velocidades de lectura / escritura extremas desde su capa de almacenamiento en caché.
Este controlador de caché está alimentado por las tablas Swoole. Todos los datos almacenados en la caché están disponibles para todos los trabajadores en el servidor. Sin embargo, los datos en caché se eliminarán cuando se reinicie el servidor:
Cache::store('octane')->put('framework', 'Laravel', 30);
Nota El número máximo de entradas permitidas en la caché de Octane puede definirse en el archivo de configuración
octane
de tu aplicación.
Además de los métodos típicos proporcionados por el sistema de caché de Laravel, el controlador de caché de Octane cuenta con cachés basadas en intervalos. Estas cachés se actualizan automáticamente en el intervalo especificado y deben registrarse dentro del método boot
de uno de los proveedores de servicios de tu aplicación. Por ejemplo, la siguiente caché se actualizará cada cinco segundos:
use Illuminate\Support\Str; Cache::store('octane')->interval('random', function () { return Str::random(10);}, seconds: 5);
Advertencia Esta característica requiere Swoole.
Al usar Swoole, puedes definir e interactuar con tus propias tablas Swoole arbitrarias. Las tablas Swoole proporcionan un rendimiento extremadamente alto y los datos en estas tablas pueden ser accesibles por todos los trabajadores en el servidor. Sin embargo, los datos dentro de ellas se perderán cuando se reinicie el servidor.
Las tablas deben definirse dentro de la matriz de configuración tables
del archivo de configuración octane
de tu aplicación. Ya se ha configurado un ejemplo de tabla que permite un máximo de 1000 filas. El tamaño máximo de las columnas de cadena se puede configurar especificando el tamaño de la columna después del tipo de columna, como se ve a continuación:
'tables' => [ 'example:1000' => [ 'name' => 'string:1000', 'votes' => 'int', ],],
Para acceder a una tabla, puedes utilizar el método Octane::table
:
use Laravel\Octane\Facades\Octane; Octane::table('example')->set('uuid', [ 'name' => 'Nuno Maduro', 'votes' => 1000,]); return Octane::table('example')->get('uuid');
Advertencia Los tipos de columna admitidos por las tablas Swoole son:
string
,int
yfloat
.