diff --git a/bin/swoole-server b/bin/swoole-server index 3fa19c249..98e57cf61 100755 --- a/bin/swoole-server +++ b/bin/swoole-server @@ -13,11 +13,13 @@ use Swoole\Timer; ini_set('display_errors', 'stderr'); -require_once __DIR__.'/../src/Stream.php'; +$basePath = getenv('APP_RELEASE_BIN_DIR'); -require __DIR__.'/../fixes/fix-symfony-dd.php'; +require_once $basePath . '/../src/Stream.php'; -$bootstrap = fn ($serverState) => require __DIR__.'/bootstrap.php'; +require $basePath . '/../fixes/fix-symfony-dd.php'; + +$bootstrap = fn($serverState) => require $basePath . '/bootstrap.php'; /* |-------------------------------------------------------------------------- @@ -34,9 +36,9 @@ $serverState = json_decode(file_get_contents( $serverStateFile = $_SERVER['argv'][1] ), true)['state']; -$server = require __DIR__.'/createSwooleServer.php'; +$server = require $basePath . '/createSwooleServer.php'; -$timerTable = require __DIR__.'/createSwooleTimerTable.php'; +$timerTable = require $basePath . '/createSwooleTimerTable.php'; /* |-------------------------------------------------------------------------- @@ -49,6 +51,10 @@ $timerTable = require __DIR__.'/createSwooleTimerTable.php'; | */ +$server->on('beforereload', function (Server $server) { + clearstatcache(true); +}); + $server->on('start', fn (Server $server) => $bootstrap($serverState) && (new OnServerStart( new ServerStateFile($serverStateFile), new SwooleExtension, @@ -58,13 +64,13 @@ $server->on('start', fn (Server $server) => $bootstrap($serverState) && (new OnS $serverState['octaneConfig']['tick'] ?? true ))($server)); -$server->on('managerstart', function () use ($serverState) { +$server->on('managerstart', function () use (&$serverState, $basePath) { // 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'; + require_once $basePath . '/../src/Swoole/Handlers/OnManagerStart.php'; + require_once $basePath . '/../src/Swoole/SwooleExtension.php'; (new OnManagerStart( - new SwooleExtension, $serverState['appName'] + new SwooleExtension, $serverState['appName'] ))(); }); @@ -83,13 +89,13 @@ $server->on('managerstart', function () use ($serverState) { | */ -require_once __DIR__.'/WorkerState.php'; +require_once $basePath . '/WorkerState.php'; $workerState = new WorkerState; -$workerState->cacheTable = require __DIR__.'/createSwooleCacheTable.php'; +$workerState->cacheTable = require $basePath . '/createSwooleCacheTable.php'; $workerState->timerTable = $timerTable; -$workerState->tables = require __DIR__.'/createSwooleTables.php'; +$workerState->tables = require $basePath . '/createSwooleTables.php'; $server->on('workerstart', fn (Server $server, $workerId) => (fn ($basePath) => (new OnWorkerStart( diff --git a/src/Commands/StartSwooleCommand.php b/src/Commands/StartSwooleCommand.php index 4d31dbc3a..ec1d3bd37 100644 --- a/src/Commands/StartSwooleCommand.php +++ b/src/Commands/StartSwooleCommand.php @@ -44,6 +44,47 @@ class StartSwooleCommand extends Command implements SignalableCommandInterface */ protected $hidden = true; + /** + * Indicates whether the command runs in a symlinked directory path. + */ + protected bool $isSymlinked = false; + + /** + * The reliable directory path to use, relative to the Octane path. + */ + protected string $dir; + + /** + * The actual path, rather than the symlinked path. + */ + protected string $real_cwd; + + /** + * The reliable working directory path of the process. + * Respects the symlink path and does not convert to the real path. + */ + protected string $pwd; + + public function __construct() + { + $this->dir = __DIR__; + $this->real_cwd = base_path(); + $this->getPwd(); + + if ($this->pwd !== $this->real_cwd) { + $this->isSymlinked = true; + $this->dir = str_replace($this->real_cwd, $this->pwd, $this->dir); + app()->setBasePath($this->pwd); + + $log_file = config('octane.swoole.options.log_file'); + if ($log_file) { + config(['octane.swoole.options.log_file' => $this->realpath($log_file)]); + } + } + + parent::__construct(); + } + /** * Handle the command. * @@ -83,9 +124,10 @@ public function handle( ...config('octane.swoole.php_options', []), config('octane.swoole.command', 'swoole-server'), $serverStateFile->path(), - ], realpath(__DIR__.'/../../bin'), [ + ], $this->realpath($this->dir.'/../../bin'), [ 'APP_ENV' => app()->environment(), 'APP_BASE_PATH' => base_path(), + 'APP_RELEASE_BIN_DIR' => $this->realpath($this->dir.'/../../bin'), 'LARAVEL_OCTANE' => 1, ]))->start(); @@ -138,6 +180,54 @@ protected function defaultServerOptions(SwooleExtension $extension) ]; } + /** + * Returns the real path of a file. If the working directory path is symlinked, + * it returns the file location relative to the reliable working directory path of the process, + * instead of the real path. + */ + protected function realpath(string $file): string + { + $realPath = realpath($file); + + if (! $this->isSymlinked) { + return $realPath; + } + + return str_replace($this->real_cwd, $this->pwd, $realPath); + } + + /** + * Determines and sets the reliable working directory path of the process. + * Respects the symlink path and does not convert to the real path. + */ + protected function getPwd(): void + { + $working_dir = dirname(request()->server('SCRIPT_NAME')); + if (($starts_as_curr = str_starts_with($working_dir, './')) || str_starts_with($working_dir, '/')) { + if ($starts_as_curr) { + $working_dir = substr($working_dir, 2); + } + + $cwd = getcwd(); + if (! str_starts_with($cwd, $working_dir)) { + $this->pwd = "$cwd/$working_dir"; + } else { + $this->pwd = $working_dir; + } + } elseif ($working_dir === '.') { + // This part comes into action only if the server changes to + // the base path directory before running the Artisan command. + // eg. cd /www/current && php artisan octane:start + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $this->pwd = trim(shell_exec('cd')); // For Windows + } else { + $this->pwd = trim(shell_exec('pwd')); // For Unix-like systems + } + } else { + $this->pwd = $this->real_cwd; + } + } + /** * Get the number of workers that should be started. *