Skip to content

Commit

Permalink
[2.x] Adds support for multiple FrankenPHP Octane instances (#777)
Browse files Browse the repository at this point in the history
* Adds support for multiple FrankenPHP Octane processes

* Improves `serverIsRunning`

* Checks if port is already in use

* Improves checking if ports are available

* formatting

---------

Co-authored-by: Taylor Otwell <taylor@laravel.com>
  • Loading branch information
nunomaduro and taylorotwell authored Dec 20, 2023
1 parent d1946dc commit 42ce8da
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 8 deletions.
43 changes: 43 additions & 0 deletions src/Commands/StartFrankenPhpCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class StartFrankenPhpCommand extends Command implements SignalableCommandInterfa
public function handle(ServerProcessInspector $inspector, ServerStateFile $serverStateFile)
{
$this->ensureFrankenPhpWorkerIsInstalled();
$this->ensureHostsAreAvailable();

$frankenphpBinary = $this->ensureFrankenPhpBinaryIsInstalled();

Expand Down Expand Up @@ -87,6 +88,7 @@ public function handle(ServerProcessInspector $inspector, ServerStateFile $serve
'APP_PUBLIC_PATH' => public_path(),
'LARAVEL_OCTANE' => 1,
'MAX_REQUESTS' => $this->option('max-requests'),
'CADDY_SERVER_ADMIN_PORT' => $this->adminPort(),
'CADDY_SERVER_LOG_LEVEL' => $this->option('log-level') ?: (app()->environment('local') ? 'INFO' : 'WARN'),
'CADDY_SERVER_LOGGER' => 'json',
'CADDY_SERVER_SERVER_NAME' => $serverName,
Expand All @@ -101,6 +103,34 @@ public function handle(ServerProcessInspector $inspector, ServerStateFile $serve
return $this->runServer($server, $inspector, 'frankenphp');
}

/**
* Ensures the server and admin localhost ports are available.
*
* @return void
*/
protected function ensureHostsAreAvailable()
{
$host = $this->getHost();

$serverPort = $this->getPort();
$adminPort = $this->adminPort();

if ($host !== '127.0.0.1') {
return;
}

foreach ([$serverPort, $adminPort] as $port) {
$connection = @fsockopen($host, $port);
$isAvailable = ! is_resource($connection);

if (! $isAvailable) {
@fclose($connection);

throw new InvalidArgumentException("Unable to start server. Port {$port} is already in use.");
}
}
}

/**
* Get the path to the FrankenPHP configuration file.
*
Expand Down Expand Up @@ -161,12 +191,25 @@ protected function writeServerStateFile(
'appName' => config('app.name', 'Laravel'),
'host' => $this->getHost(),
'port' => $this->getPort(),
'adminPort' => $this->adminPort(),
'workers' => $this->workerCount(),
'maxRequests' => $this->option('max-requests'),
'octaneConfig' => config('octane'),
]);
}

/**
* Get the port the admin URL should be available on.
*
* @return int
*/
protected function adminPort()
{
$defaultPort = 2019;

return $defaultPort + ($this->getPort() - 8000);
}

/**
* Get the number of workers that should be started.
*
Expand Down
2 changes: 2 additions & 0 deletions src/Commands/stubs/Caddyfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
{$CADDY_GLOBAL_OPTIONS}

admin localhost:{$CADDY_SERVER_ADMIN_PORT}

frankenphp {
worker {$APP_PUBLIC_PATH}/frankenphp-worker.php {$CADDY_SERVER_WORKER_COUNT}
}
Expand Down
37 changes: 29 additions & 8 deletions src/FrankenPhp/ServerProcessInspector.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@

class ServerProcessInspector implements ServerProcessInspectorContract
{
private const ADMIN_URL = 'http://localhost:2019';

private const FRANKENPHP_CONFIG_URL = self::ADMIN_URL.'/config/apps/frankenphp';

/**
* Create a new server process inspector instance.
*/
public function __construct(
protected ServerStateFile $serverStateFile,
) {
Expand All @@ -23,8 +22,12 @@ public function __construct(
*/
public function serverIsRunning(): bool
{
if (is_null($this->serverStateFile->read()['masterProcessId'] ?? null)) {
return false;
}

try {
return Http::get(self::FRANKENPHP_CONFIG_URL)->successful();
return Http::get($this->adminConfigUrl())->successful();
} catch (ConnectionException $_) {
return false;
}
Expand All @@ -36,9 +39,9 @@ public function serverIsRunning(): bool
public function reloadServer(): void
{
try {
Http::withBody(Http::get(self::FRANKENPHP_CONFIG_URL)->body(), 'application/json')
Http::withBody(Http::get($this->adminConfigUrl())->body(), 'application/json')
->withHeaders(['Cache-Control' => 'must-revalidate'])
->patch(self::FRANKENPHP_CONFIG_URL);
->patch($this->adminConfigUrl());
} catch (ConnectionException $_) {
//
}
Expand All @@ -50,9 +53,27 @@ public function reloadServer(): void
public function stopServer(): bool
{
try {
return Http::post(self::ADMIN_URL.'/stop')->successful();
return Http::post($this->adminUrl().'/stop')->successful();
} catch (ConnectionException $_) {
return false;
}
}

/**
* Get the URL to the FrankenPHP admin panel.
*/
protected function adminUrl(): string
{
$adminPort = $this->serverStateFile->read()['state']['adminPort'] ?? 2019;

return "http://localhost:{$adminPort}";
}

/**
* Get the URL to the FrankenPHP admin panel's configuration endpoint.
*/
protected function adminConfigUrl(): string
{
return "{$this->adminUrl()}/config/apps/frankenphp";
}
}

0 comments on commit 42ce8da

Please sign in to comment.