-
Notifications
You must be signed in to change notification settings - Fork 304
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[2.x] Add support for FrankenPHP (#764)
* Add support for FrankenPHP * make linters happy * Update src/Commands/StatusCommand.php Co-authored-by: William Desportes <[email protected]> * use a static closure in the worker script Co-authored-by: Francis Lavoie <[email protected]> * tabs Co-authored-by: Francis Lavoie <[email protected]> * tabs Co-authored-by: Francis Lavoie <[email protected]> * tabs Co-authored-by: Francis Lavoie <[email protected]> * tabs Co-authored-by: Francis Lavoie <[email protected]> * use match * fix vuln and simplify config * cs * @francislavoie review * Update StartFrankenPhpCommand.php Co-authored-by: Kennedy Tedesco <[email protected]> * Update frankenphp-worker.php Co-authored-by: Kennedy Tedesco <[email protected]> * Update InstallCommand.php Co-authored-by: Kennedy Tedesco <[email protected]> * docs: update README and composer.json * cs * phpstan * simplify * cs * better Caddyfile * Update octane.php Co-authored-by: Shalvah <[email protected]> * fix error handling * disable debug mode as it's slow * Fix swoole and octane write server running * fix: ignore user abort * feat: download the stable version * follow symlinks * improve perf * fix non-tty mode * formatting * formatting * formatting * formatting * formatting * formatting * performance * fix log level support * more robust log level handling in Mercure block * fix logs * better logging handling * cs * cs * missing changes in Caddyfile * Updates changelog * Prettify output * cs * Displays regular error messages * Ensures binary is up-to-date * Ensures binary is up-to-date * Removes mercure * Removes unused warning * Publishes only a simple require * Style * Cleans up code * Uses `--caddyfile` * Fixes catch * formatting * Fixes log output * Fix bug * Removes non-needed comments * Prefixes caddy environment variables * Reports worker exceptions * Displays anything different from 200 * Shutdowns on server exception boot * Fixes 500 responses from worker * Don't publish caddyfile * Fixes double realpath call * Fixes method name * Dont ignore caddy * Fix logs in non local * warn * dont report to master * Fixes method "put" not getting caught * Uses mercure `demo` when requested * Don't display mercure stuff * Adds link to readme: * Update README.md * Update InstallsFrankenPhpDependencies.php * Update InstallCommand.php * Update StartCommand.php * Update StartFrankenPhpCommand.php --------- Co-authored-by: William Desportes <[email protected]> Co-authored-by: Francis Lavoie <[email protected]> Co-authored-by: Kennedy Tedesco <[email protected]> Co-authored-by: Shalvah <[email protected]> Co-authored-by: Nuno Maduro <[email protected]> Co-authored-by: Taylor Otwell <[email protected]>
- Loading branch information
1 parent
1014bc6
commit a468648
Showing
29 changed files
with
1,001 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,3 +13,6 @@ trim_trailing_whitespace = false | |
|
||
[*.{yml,yaml}] | ||
indent_size = 2 | ||
|
||
[Caddyfile] | ||
indent_style = tab |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<?php | ||
|
||
use Laravel\Octane\ApplicationFactory; | ||
use Laravel\Octane\FrankenPhp\FrankenPhpClient; | ||
use Laravel\Octane\RequestContext; | ||
use Laravel\Octane\Stream; | ||
use Laravel\Octane\Worker; | ||
use Symfony\Component\HttpFoundation\Response; | ||
use Throwable; | ||
|
||
if ((! ($_SERVER['FRANKENPHP_WORKER'] ?? false)) || ! function_exists('frankenphp_handle_request')) { | ||
echo 'FrankenPHP must be in worker mode to use this script.'; | ||
|
||
exit(1); | ||
} | ||
|
||
ignore_user_abort(true); | ||
|
||
$basePath = require __DIR__.'/bootstrap.php'; | ||
|
||
/* | ||
|-------------------------------------------------------------------------- | ||
| Start The Octane Worker | ||
|-------------------------------------------------------------------------- | ||
| | ||
| Next we will start the Octane worker, which is a long running process to | ||
| handle incoming requests to the application. This worker will be used | ||
| by FrankenPHP to serve an entire Laravel application at high speed. | ||
| | ||
*/ | ||
|
||
$frankenPhpClient = new FrankenPhpClient(); | ||
|
||
$worker = null; | ||
$requestCount = 0; | ||
$maxRequests = $_ENV['MAX_REQUESTS'] ?? $_SERVER['MAX_REQUESTS']; | ||
|
||
try { | ||
$handleRequest = static function () use (&$worker, $basePath, $frankenPhpClient) { | ||
try { | ||
$worker ??= tap( | ||
new Worker( | ||
new ApplicationFactory($basePath), $frankenPhpClient | ||
) | ||
)->boot(); | ||
|
||
[$request, $context] = $frankenPhpClient->marshalRequest(new RequestContext()); | ||
|
||
$worker->handle($request, $context); | ||
} catch (Throwable $e) { | ||
if ($worker) { | ||
report($e); | ||
} | ||
|
||
$response = new Response( | ||
'Internal Server Error', | ||
500, | ||
[ | ||
'Status' => '500 Internal Server Error', | ||
'Content-Type' => 'text/plain', | ||
], | ||
); | ||
|
||
$response->send(); | ||
|
||
Stream::shutdown($e); | ||
} | ||
}; | ||
|
||
while ($requestCount < $maxRequests && frankenphp_handle_request($handleRequest)) { | ||
$requestCount++; | ||
} | ||
} finally { | ||
$worker?->terminate(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
163 changes: 163 additions & 0 deletions
163
src/Commands/Concerns/InstallsFrankenPhpDependencies.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
<?php | ||
|
||
namespace Laravel\Octane\Commands\Concerns; | ||
|
||
use GuzzleHttp\Client; | ||
use Illuminate\Support\Facades\Http; | ||
use Laravel\Octane\FrankenPhp\Concerns\FindsFrankenPhpBinary; | ||
use Symfony\Component\Process\Process; | ||
use Throwable; | ||
|
||
trait InstallsFrankenPhpDependencies | ||
{ | ||
use FindsFrankenPhpBinary; | ||
|
||
/** | ||
* The minimum required version of the FrankenPHP binary. | ||
* | ||
* @var string | ||
*/ | ||
protected $requiredFrankenPhpVersion = '1.0.0'; | ||
|
||
/** | ||
* Ensure the FrankenPHP's Caddyfile and worker script are installed. | ||
* | ||
* @return void | ||
*/ | ||
public function ensureFrankenPhpWorkerIsInstalled() | ||
{ | ||
if (! file_exists(public_path('frankenphp-worker.php'))) { | ||
copy(__DIR__.'/../stubs/frankenphp-worker.php', public_path('frankenphp-worker.php')); | ||
} | ||
} | ||
|
||
/** | ||
* Ensure the FrankenPHP binary is installed into the project. | ||
* | ||
* @return string | ||
*/ | ||
protected function ensureFrankenPhpBinaryIsInstalled() | ||
{ | ||
if (! is_null($frankenphpBinary = $this->findFrankenPhpBinary())) { | ||
return $frankenphpBinary; | ||
} | ||
|
||
if ($this->confirm('Unable to locate FrankenPHP binary. Should Octane download the binary for your operating system?', true)) { | ||
$this->downloadFrankenPhpBinary(); | ||
} | ||
|
||
return base_path('frankenphp'); | ||
} | ||
|
||
/** | ||
* Download the latest version of the FrankenPHP binary. | ||
* | ||
* @return bool | ||
*/ | ||
protected function downloadFrankenPhpBinary() | ||
{ | ||
$arch = php_uname('m'); | ||
|
||
$assetName = match (true) { | ||
PHP_OS_FAMILY === 'Linux' && $arch === 'x86_64' => 'frankenphp-linux-x86_64', | ||
PHP_OS_FAMILY === 'Darwin' => "frankenphp-mac-$arch", | ||
default => null, | ||
}; | ||
|
||
if ($assetName === null) { | ||
$this->error('FrankenPHP binaries are currently only available for Linux (x86_64) and macOS. Other systems should use the Docker images or compile FrankenPHP manually.'); | ||
|
||
return false; | ||
} | ||
|
||
$assets = Http::accept('application/vnd.github+json') | ||
->withHeaders(['X-GitHub-Api-Version' => '2022-11-28']) | ||
->get('https://api.github.com/repos/dunglas/frankenphp/releases/latest')['assets']; | ||
|
||
foreach ($assets as $asset) { | ||
if ($asset['name'] !== $assetName) { | ||
continue; | ||
} | ||
|
||
$path = base_path('frankenphp'); | ||
|
||
$progressBar = null; | ||
|
||
(new Client)->get( | ||
$asset['browser_download_url'], | ||
[ | ||
'sink' => $path, | ||
'progress' => function ($downloadTotal, $downloadedBytes) use (&$progressBar) { | ||
if ($downloadTotal === 0) { | ||
return; | ||
} | ||
|
||
if ($progressBar === null) { | ||
$progressBar = $this->output->createProgressBar($downloadTotal); | ||
$progressBar->start($downloadTotal, $downloadedBytes); | ||
|
||
return; | ||
} | ||
|
||
$progressBar->setProgress($downloadedBytes); | ||
}, | ||
] | ||
); | ||
|
||
chmod($path, 0755); | ||
|
||
$progressBar->finish(); | ||
|
||
$this->newLine(); | ||
|
||
return $path; | ||
} | ||
|
||
$this->error('FrankenPHP asset not found.'); | ||
|
||
return $path; | ||
} | ||
|
||
/** | ||
* Ensure the installed FrankenPHP binary meets Octane's requirements. | ||
* | ||
* @param string $frakenPhpBinary | ||
* @return void | ||
*/ | ||
protected function ensureFrankenPhpBinaryMeetsRequirements($frakenPhpBinary) | ||
{ | ||
$version = tap(new Process([$frakenPhpBinary, '--version'], base_path())) | ||
->run() | ||
->getOutput(); | ||
|
||
$version = explode(' ', $version)[1] ?? null; | ||
|
||
if ($version === null) { | ||
return $this->warn( | ||
'Unable to determine the current FrankenPHP binary version. Please report this issue: https://github.com/laravel/octane/issues/new.', | ||
); | ||
} | ||
|
||
if (version_compare($version, $this->requiredFrankenPhpVersion, '>=')) { | ||
return; | ||
} | ||
|
||
$this->warn("Your FrankenPHP binary version (<fg=red>$version</>) may be incompatible with Octane."); | ||
|
||
if ($this->confirm('Should Octane download the latest FrankenPHP binary version for your operating system?', true)) { | ||
rename($frakenPhpBinary, "$frakenPhpBinary.backup"); | ||
|
||
try { | ||
$this->downloadFrankenPhpBinary(); | ||
} catch (Throwable $e) { | ||
report($e); | ||
|
||
rename("$frakenPhpBinary.backup", $frakenPhpBinary); | ||
|
||
return $this->warn('Unable to download FrankenPHP binary. The HTTP request exception has been logged.'); | ||
} | ||
|
||
unlink("$frakenPhpBinary.backup"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.