173 lines
5.8 KiB
PHP
Executable File
173 lines
5.8 KiB
PHP
Executable File
#!/usr/bin/env php
|
|
<?php
|
|
|
|
use Laravel\Octane\RequestContext;
|
|
use Laravel\Octane\Swoole\Handlers\OnManagerStart;
|
|
use Laravel\Octane\Swoole\Handlers\OnServerStart;
|
|
use Laravel\Octane\Swoole\Handlers\OnWorkerStart;
|
|
use Laravel\Octane\Swoole\ServerStateFile;
|
|
use Laravel\Octane\Swoole\SwooleExtension;
|
|
use Laravel\Octane\Swoole\WorkerState;
|
|
use Swoole\Http\Server;
|
|
use Swoole\Timer;
|
|
|
|
ini_set('display_errors', 'stderr');
|
|
|
|
require_once __DIR__.'/../src/Stream.php';
|
|
|
|
require __DIR__.'/../fixes/fix-symfony-dd.php';
|
|
|
|
$bootstrap = fn ($serverState) => require __DIR__.'/bootstrap.php';
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Create The Swoole Server
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| First, we will load the server state file from disk. This file contains
|
|
| various information we need to boot Swoole such as the configuration
|
|
| and application name. We can use this data to start up our server.
|
|
|
|
|
*/
|
|
|
|
$serverState = json_decode(file_get_contents(
|
|
$serverStateFile = $_SERVER['argv'][1]
|
|
), true)['state'];
|
|
|
|
$server = require __DIR__.'/createSwooleServer.php';
|
|
|
|
$timerTable = require __DIR__.'/createSwooleTimerTable.php';
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Handle Server & Manager Start
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| The following callbacks manage the master process and manager process
|
|
| start events. These handlers primarily are responsible for writing
|
|
| the process ID to the server state file so we can remember them.
|
|
|
|
|
*/
|
|
|
|
$server->on('start', fn (Server $server) => $bootstrap($serverState) && (new OnServerStart(
|
|
new ServerStateFile($serverStateFile),
|
|
new SwooleExtension,
|
|
$serverState['appName'],
|
|
$serverState['octaneConfig']['max_execution_time'] ?? 0,
|
|
$timerTable,
|
|
$serverState['octaneConfig']['tick'] ?? true
|
|
))($server));
|
|
|
|
$server->on('managerstart', function () use ($serverState) {
|
|
// Don't bootstrap entire application before server / worker start. Otherwise, files can't be gracefully reloaded... #632
|
|
require_once __DIR__.'/../src/Swoole/Handlers/OnManagerStart.php';
|
|
require_once __DIR__.'/../src/Swoole/SwooleExtension.php';
|
|
|
|
(new OnManagerStart(
|
|
new SwooleExtension, $serverState['appName']
|
|
))();
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Handle Worker Start
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Swoole will start multiple worker processes and the following callback
|
|
| will handle their state events. When a worker starts we will create
|
|
| a new Octane worker and inform it to start handling our requests.
|
|
|
|
|
| We will also create a "workerState" variable which will maintain state
|
|
| and allow us to access the worker and client from the callback that
|
|
| will handle incoming requests. Basically this works like a cache.
|
|
|
|
|
*/
|
|
|
|
require_once __DIR__.'/WorkerState.php';
|
|
|
|
$workerState = new WorkerState;
|
|
|
|
$workerState->cacheTable = require __DIR__.'/createSwooleCacheTable.php';
|
|
$workerState->timerTable = $timerTable;
|
|
$workerState->tables = require __DIR__.'/createSwooleTables.php';
|
|
|
|
$server->on('workerstart', fn (Server $server, $workerId) =>
|
|
(fn ($basePath) => (new OnWorkerStart(
|
|
new SwooleExtension, $basePath, $serverState, $workerState
|
|
))($server, $workerId))($bootstrap($serverState))
|
|
);
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Handle Incoming Requests
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| The following callback will handle all incoming requests plus send them
|
|
| the worker. The worker will send the request through the application
|
|
| and ask the client to send the response back to the Swoole server.
|
|
|
|
|
*/
|
|
|
|
$server->on('request', function ($request, $response) use ($server, $workerState, $serverState) {
|
|
$workerState->lastRequestTime = microtime(true);
|
|
|
|
if ($workerState->timerTable) {
|
|
$workerState->timerTable->set($workerState->workerId, [
|
|
'worker_pid' => $workerState->workerPid,
|
|
'time' => time(),
|
|
'fd' => $request->fd,
|
|
]);
|
|
}
|
|
|
|
$workerState->worker->handle(...$workerState->client->marshalRequest(new RequestContext([
|
|
'swooleRequest' => $request,
|
|
'swooleResponse' => $response,
|
|
'publicPath' => $serverState['publicPath'],
|
|
'octaneConfig' => $serverState['octaneConfig'],
|
|
])));
|
|
|
|
if ($workerState->timerTable) {
|
|
$workerState->timerTable->del($workerState->workerId);
|
|
}
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Handle Tasks
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Swoole tasks can be used to offload concurrent work onto a group of
|
|
| background processes which handle the work in isolation and with
|
|
| separate application state. We should handle these tasks below.
|
|
|
|
|
*/
|
|
|
|
$server->on('task', fn (Server $server, int $taskId, int $fromWorkerId, $data) =>
|
|
$data === 'octane-tick'
|
|
? $workerState->worker->handleTick()
|
|
: $workerState->worker->handleTask($data)
|
|
);
|
|
|
|
$server->on('finish', fn (Server $server, int $taskId, $result) => $result);
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Handle Worker & Server Shutdown
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| The following callbacks handle the master and worker shutdown events so
|
|
| we can clean up any state, including the server state file. An event
|
|
| will be dispatched by the worker so the developer can take action.
|
|
|
|
|
*/
|
|
|
|
$server->on('workerstop', function () use ($workerState) {
|
|
if ($workerState->tickTimerId) {
|
|
Timer::clear($workerState->tickTimerId);
|
|
}
|
|
|
|
$workerState->worker->terminate();
|
|
});
|
|
|
|
$server->start();
|