Skip to content
This repository has been archived by the owner on Jan 17, 2022. It is now read-only.

Commit

Permalink
fix(reload): Make sure command works on macOS system
Browse files Browse the repository at this point in the history
  • Loading branch information
k911 committed Apr 6, 2019
1 parent 853f0a7 commit 4d99e9c
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 36 deletions.
22 changes: 15 additions & 7 deletions src/Client/HttpClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace K911\Swoole\Client;

use Assert\Assertion;
use Swoole\Coroutine;
use Swoole\Coroutine\Http\Client;

/**
Expand All @@ -30,6 +31,11 @@ final class HttpClient
self::CONTENT_TYPE_APPLICATION_JSON,
self::CONTENT_TYPE_TEXT_PLAIN,
];
private const ACCEPTABLE_CONNECTING_EXIT_CODES = [
111 => true,
61 => true,
60 => true,
];

private $client;

Expand All @@ -39,27 +45,29 @@ public function __construct(Client $client)
}

/**
* @param int $timeout seconds
* @param int $step microseconds
* @param int $timeout seconds
* @param float $step microseconds
*
* @return bool Success
*/
public function connect(int $timeout = 3, int $step = 500): bool
public function connect(int $timeout = 3, float $step = 0.1): bool
{
$timeoutMicro = \microtime(true) + $timeout;
$start = \microtime(true);
$max = $start + $timeout;

do {
try {
$this->send('/', 'HEAD');

return true;
} catch (\RuntimeException $ex) {
if (111 !== $ex->getCode()) {
if (!isset(self::ACCEPTABLE_CONNECTING_EXIT_CODES[$ex->getCode()])) {
throw $ex;
}
}
\usleep($step);
} while (\microtime(true) < $timeoutMicro);
Coroutine::sleep($step);
$now = \microtime(true);
} while ($now < $max);

return false;
}
Expand Down
9 changes: 7 additions & 2 deletions src/Server/HttpServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@ final class HttpServer

private $running;
private $configuration;
private $signalTerminate;
private $signalReload;

public function __construct(HttpServerConfiguration $configuration, bool $running = false)
{
$this->signalTerminate = \defined('SIGTERM') ? (int) \constant('SIGTERM') : 15;
$this->signalReload = \defined('SIGUSR1') ? (int) \constant('SIGUSR1') : 10;

$this->running = $running;
$this->configuration = $configuration;
}
Expand Down Expand Up @@ -60,7 +65,7 @@ public function shutdown(): void
if ($this->server instanceof Server) {
$this->server->shutdown();
} elseif ($this->isRunningInBackground()) {
Process::kill($this->configuration->getPid(), 15); // SIGTERM
Process::kill($this->configuration->getPid(), $this->signalTerminate);
} else {
throw new RuntimeException('Swoole HTTP Server has not been running.');
}
Expand All @@ -74,7 +79,7 @@ public function reload(): void
if ($this->server instanceof Server) {
$this->server->reload();
} elseif ($this->isRunningInBackground()) {
Process::kill($this->configuration->getPid(), 10); // SIGUSR1
Process::kill($this->configuration->getPid(), $this->signalReload);
} else {
throw new RuntimeException('Swoole HTTP Server has not been running.');
}
Expand Down
17 changes: 13 additions & 4 deletions src/Server/Runtime/HMR/InotifyHMR.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace K911\Swoole\Server\Runtime\HMR;

use Assert\Assertion;
use Assert\AssertionFailedException;
use K911\Swoole\Server\Runtime\BootableInterface;
use Swoole\Server;

Expand All @@ -25,20 +26,28 @@ final class InotifyHMR implements HotModuleReloaderInterface, BootableInterface
*/
private $inotify;

/**
* @var int \IN_ATRIB
*/
private $watchMask;

/**
* @param array $nonReloadableFiles
*
* @throws \Assert\AssertionFailedException
* @throws AssertionFailedException
*/
public function __construct(array $nonReloadableFiles = [])
{
Assertion::extensionLoaded('inotify', 'Swoole HMR requires "inotify" PHP Extension present and loaded in the system.');
$this->watchMask = \defined('IN_ATTRIB') ? (int) \constant('IN_ATTRIB') : 4;

$this->setNonReloadableFiles($nonReloadableFiles);
}

/**
* @param string[] $nonReloadableFiles files
*
* @throws \Assert\AssertionFailedException
* @throws AssertionFailedException
*/
private function setNonReloadableFiles(array $nonReloadableFiles): void
{
Expand All @@ -55,7 +64,7 @@ private function watchFiles(array $files): void
{
foreach ($files as $file) {
if (!isset($this->nonReloadableFiles[$file]) && !isset($this->watchedFiles[$file])) {
$this->watchedFiles[$file] = \inotify_add_watch($this->inotify, $file, IN_ATTRIB);
$this->watchedFiles[$file] = \inotify_add_watch($this->inotify, $file, $this->watchMask);
}
}
}
Expand All @@ -79,7 +88,7 @@ public function tick(Server $server): void
/**
* {@inheritdoc}
*
* @throws \Assert\AssertionFailedException
* @throws AssertionFailedException
*/
public function boot(array $runtimeConfiguration = []): void
{
Expand Down
4 changes: 4 additions & 0 deletions tests/Feature/SwooleServerHMRTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ final class SwooleServerHMRTest extends ServerTestCase

public function testStartCallHMRCallStop(): void
{
if (!\extension_loaded('inotify')) {
$this->markTestSkipped('Swoole Bundle HMR requires "inotify" PHP extension present and installed on the system.');
}

$serverStart = $this->createConsoleProcess([
'swoole:server:start',
'--host=localhost',
Expand Down
23 changes: 17 additions & 6 deletions tests/Feature/SwooleServerReloadCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use K911\Swoole\Client\HttpClient;
use K911\Swoole\Tests\Fixtures\Symfony\TestBundle\Test\ServerTestCase;
use Swoole\Coroutine;
use Symfony\Component\Process\Exception\ProcessFailedException;

final class SwooleServerReloadCommandTest extends ServerTestCase
{
Expand All @@ -23,7 +24,9 @@ public function testStartCallReloadCallStop(): void
'--port=9999',
]);

$serverStart->disableOutput();
if ($this->coverageEnabled()) {
$serverStart->disableOutput();
}
$serverStart->setTimeout(3);
$serverStart->run();

Expand Down Expand Up @@ -62,13 +65,21 @@ public function testStartCallReloadCallStop(): void

private function runSwooleServerReload(): void
{
$serverStart = $this->createConsoleProcess(['swoole:server:reload']);
$serverReload = $this->createConsoleProcess(['swoole:server:reload']);

$serverStart->disableOutput();
$serverStart->setTimeout(3);
$serverStart->run();
if ($this->coverageEnabled()) {
$serverReload->disableOutput();
}
$serverReload->setTimeout(3);
$serverReload->run();

$this->assertTrue($serverStart->isSuccessful());
if (!$serverReload->isSuccessful()) {
throw new ProcessFailedException($serverReload);
}

if (!$this->coverageEnabled()) {
$this->assertStringContainsString('Swoole HTTP Server\'s workers reloaded successfully', $serverReload->getOutput());
}
}

private function replaceContentInTestController(string $text): void
Expand Down
14 changes: 8 additions & 6 deletions tests/Feature/SwooleServerRunCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,20 @@ final class SwooleServerRunCommandTest extends ServerTestCase
{
public function testRunAndCall(): void
{
$server = $this->createConsoleProcess([
$serverRun = $this->createConsoleProcess([
'swoole:server:run',
'--host=localhost',
'--port=9999',
]);

$server->disableOutput();
$server->setTimeout(10);
$server->start();
if ($this->coverageEnabled()) {
$serverRun->disableOutput();
}
$serverRun->setTimeout(10);
$serverRun->start();

$this->goAndWait(function () use ($server): void {
$this->deferProcessStop($server);
$this->goAndWait(function () use ($serverRun): void {
$this->deferProcessStop($serverRun);

$client = HttpClient::fromDomain('localhost', 9999, false);
$this->assertTrue($client->connect());
Expand Down
4 changes: 3 additions & 1 deletion tests/Feature/SwooleServerStartStopCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ public function testStartCallStop(): void
'--port=9999',
]);

$serverStart->disableOutput();
if ($this->coverageEnabled()) {
$serverStart->disableOutput();
}
$serverStart->setTimeout(3);
$serverStart->run();

Expand Down
35 changes: 25 additions & 10 deletions tests/Fixtures/Symfony/TestBundle/Test/ServerTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace K911\Swoole\Tests\Fixtures\Symfony\TestBundle\Test;

use K911\Swoole\Tests\Fixtures\Symfony\TestAppKernel;
use PHPUnit\Framework\Exception;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;
Expand Down Expand Up @@ -43,20 +44,26 @@ protected static function getKernelClass(): string
return TestAppKernel::class;
}

public function go(callable $callable): void
private function wrapAndTrap(callable $callable): callable
{
try {
\go($callable);
} catch (\RuntimeException $runtimeException) {
if (self::SWOOLE_XDEBUG_CORO_WARNING_MESSAGE !== $runtimeException->getMessage()) {
throw $runtimeException;
return function () use ($callable): void {
try {
$callable();
} catch (Exception $failedException) {
throw $failedException;
} catch (\RuntimeException $runtimeException) {
if (self::SWOOLE_XDEBUG_CORO_WARNING_MESSAGE !== $runtimeException->getMessage()) {
throw $runtimeException;
}
} catch (\Throwable $exception) {
throw $exception;
}
}
};
}

public function goAndWait(callable $callable): void
{
$this->go($callable);
\go($this->wrapAndTrap($callable));
\swoole_event_wait();
}

Expand All @@ -81,11 +88,19 @@ public function deferServerStop(): void
\defer(function (): void {
$serverStop = $this->createConsoleProcess(['swoole:server:stop']);

$serverStop->disableOutput();
if ($this->coverageEnabled()) {
$serverStop->disableOutput();
}
$serverStop->setTimeout(3);
$serverStop->run();

$this->assertTrue($serverStop->isSuccessful());
if (!$serverStop->isSuccessful()) {
throw new ProcessFailedException($serverStop);
}

if (!$this->coverageEnabled()) {
$this->assertStringContainsString('Swoole server shutdown successfully', $serverStop->getOutput());
}
});
}

Expand Down
7 changes: 7 additions & 0 deletions tests/Unit/Server/Runtime/HMR/InotifyHMRTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ class InotifyHMRTest extends TestCase
__DIR__.'/InotifyHMRTest.php',
];

protected function setUp(): void
{
if (!\extension_loaded('inotify')) {
$this->markTestSkipped('Swoole Bundle HMR requires "inotify" PHP extension present and installed on the system.');
}
}

public function testConstructSetGetNonReloadableFiles(): void
{
$hmr = new InotifyHMR(self::NON_RELOADABLE_EXISTING_FILES);
Expand Down

0 comments on commit 4d99e9c

Please sign in to comment.