Skip to content

Commit 40a5639

Browse files
authored
Merge pull request #752 from inertiajs/ssr-health-check
[2.x] Added `inertia:check-ssr` Artisan command and `isHealthy()` method on `HttpGateway`
2 parents 393c98a + f917ff2 commit 40a5639

File tree

6 files changed

+135
-9
lines changed

6 files changed

+135
-9
lines changed

src/Commands/CheckSsr.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace Inertia\Commands;
4+
5+
use Illuminate\Console\Command;
6+
use Inertia\Ssr\Gateway;
7+
use Inertia\Ssr\HasHealthCheck;
8+
use Symfony\Component\Console\Attribute\AsCommand;
9+
10+
#[AsCommand(name: 'inertia:check-ssr')]
11+
class CheckSsr extends Command
12+
{
13+
/**
14+
* The console command name.
15+
*
16+
* @var string
17+
*/
18+
protected $signature = 'inertia:check-ssr';
19+
20+
/**
21+
* The console command description.
22+
*
23+
* @var string
24+
*/
25+
protected $description = 'Check the Inertia SSR server health status';
26+
27+
/**
28+
* check the SSR server via a Node process.
29+
*/
30+
public function handle(Gateway $gateway): int
31+
{
32+
if (! $gateway instanceof HasHealthCheck) {
33+
$this->error('The SSR gateway does not support health checks.');
34+
35+
return self::FAILURE;
36+
}
37+
38+
($check = $gateway->isHealthy())
39+
? $this->info('Inertia SSR server is running.')
40+
: $this->error('Inertia SSR server is not running.');
41+
42+
return $check ? self::SUCCESS : self::FAILURE;
43+
}
44+
}

src/ServiceProvider.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ protected function registerConsoleCommands(): void
6868
Commands\CreateMiddleware::class,
6969
Commands\StartSsr::class,
7070
Commands\StopSsr::class,
71+
Commands\CheckSsr::class,
7172
]);
7273
}
7374

src/Ssr/HasHealthCheck.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Inertia\Ssr;
4+
5+
interface HasHealthCheck
6+
{
7+
/**
8+
* Determine if the SSR server is healthy.
9+
*/
10+
public function isHealthy(): bool;
11+
}

src/Ssr/HttpGateway.php

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
use Exception;
66
use Illuminate\Http\Client\StrayRequestException;
77
use Illuminate\Support\Facades\Http;
8+
use Illuminate\Support\Str;
89

9-
class HttpGateway implements Gateway
10+
class HttpGateway implements Gateway, HasHealthCheck
1011
{
1112
/**
1213
* Dispatch the Inertia page to the Server Side Rendering engine.
@@ -21,7 +22,7 @@ public function dispatch(array $page): ?Response
2122
return null;
2223
}
2324

24-
if (! $url = $this->getHttpUrl()) {
25+
if (! $url = $this->getUrl('/render')) {
2526
return null;
2627
}
2728

@@ -45,6 +46,14 @@ public function dispatch(array $page): ?Response
4546
);
4647
}
4748

49+
/**
50+
* Determine if the SSR server is healthy.
51+
*/
52+
public function isHealthy(): bool
53+
{
54+
return Http::get($this->getUrl('/health'))->successful();
55+
}
56+
4857
/**
4958
* Determine if dispatch should proceed even if no bundle is detected.
5059
*/
@@ -62,10 +71,12 @@ protected function bundleExists(): bool
6271
}
6372

6473
/**
65-
* Get the SSR URL from the configuration, ensuring it ends with '/render'.
74+
* Get the SSR URL from the configuration, ensuring it ends with '/{$path}'.
6675
*/
67-
public function getHttpUrl(): ?string
76+
public function getUrl(string $path): ?string
6877
{
69-
return str_replace('/render', '', rtrim(config('inertia.ssr.url', 'http://127.0.0.1:13714'), '/')).'/render';
78+
$path = Str::start($path, '/');
79+
80+
return str_replace($path, '', rtrim(config('inertia.ssr.url', 'http://127.0.0.1:13714'), '/')).$path;
7081
}
7182
}

tests/Commands/CheckSsrTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace Inertia\Tests;
4+
5+
use Inertia\Ssr\Gateway;
6+
use Inertia\Ssr\HttpGateway;
7+
8+
class CheckSsrTest extends TestCase
9+
{
10+
public function test_success_on_healthy_ssr_server()
11+
{
12+
$this->mock(HttpGateway::class, fn ($mock) => $mock
13+
->shouldReceive('isHealthy')
14+
->andReturnTrue()
15+
->getMock()
16+
);
17+
18+
$this->artisan('inertia:check-ssr')
19+
->expectsOutput('Inertia SSR server is running.')
20+
->assertExitCode(0);
21+
}
22+
23+
public function test_failure_on_unhealthy_ssr_server()
24+
{
25+
$this->mock(HttpGateway::class, fn ($mock) => $mock
26+
->shouldReceive('isHealthy')
27+
->andReturnFalse()
28+
->getMock()
29+
);
30+
31+
$this->artisan('inertia:check-ssr')
32+
->expectsOutput('Inertia SSR server is not running.')
33+
->assertExitCode(1);
34+
}
35+
36+
public function test_failure_on_unsupported_gateway()
37+
{
38+
$this->mock(Gateway::class);
39+
40+
$this->artisan('inertia:check-ssr')
41+
->expectsOutput('The SSR gateway does not support health checks.')
42+
->assertExitCode(1);
43+
}
44+
}

tests/HttpGatewayTest.php

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@ class HttpGatewayTest extends TestCase
99
{
1010
protected HttpGateway $gateway;
1111

12+
protected string $renderUrl;
13+
1214
protected function setUp(): void
1315
{
1416
parent::setUp();
1517

1618
$this->gateway = new HttpGateway;
19+
$this->renderUrl = $this->gateway->getUrl('render');
1720

1821
Http::preventStrayRequests();
1922
}
@@ -46,7 +49,7 @@ public function test_it_uses_the_configured_http_url_when_the_bundle_file_is_det
4649
]);
4750

4851
Http::fake([
49-
$this->gateway->getHttpUrl() => Http::response(json_encode([
52+
$this->renderUrl => Http::response(json_encode([
5053
'head' => ['<title>SSR Test</title>', '<style></style>'],
5154
'body' => '<div id="app">SSR Response</div>',
5255
])),
@@ -69,7 +72,7 @@ public function test_it_uses_the_configured_http_url__when_bundle_file_detection
6972
]);
7073

7174
Http::fake([
72-
$this->gateway->getHttpUrl() => Http::response(json_encode([
75+
$this->renderUrl => Http::response(json_encode([
7376
'head' => ['<title>SSR Test</title>', '<style></style>'],
7477
'body' => '<div id="app">SSR Response</div>',
7578
])),
@@ -91,7 +94,7 @@ public function test_it_returns_null_when_the_http_request_fails()
9194
]);
9295

9396
Http::fake([
94-
$this->gateway->getHttpUrl() => Http::response(null, 500),
97+
$this->renderUrl => Http::response(null, 500),
9598
]);
9699

97100
$this->assertNull($this->gateway->dispatch(['page' => self::EXAMPLE_PAGE_OBJECT]));
@@ -105,9 +108,21 @@ public function test_it_returns_null_when_invalid_json_is_returned()
105108
]);
106109

107110
Http::fake([
108-
$this->gateway->getHttpUrl() => Http::response('invalid json'),
111+
$this->renderUrl => Http::response('invalid json'),
109112
]);
110113

111114
$this->assertNull($this->gateway->dispatch(['page' => self::EXAMPLE_PAGE_OBJECT]));
112115
}
116+
117+
public function test_health_check_the_ssr_server()
118+
{
119+
Http::fake([
120+
$this->gateway->getUrl('health') => Http::sequence()
121+
->push(status: 200)
122+
->push(status: 500),
123+
]);
124+
125+
$this->assertTrue($this->gateway->isHealthy());
126+
$this->assertFalse($this->gateway->isHealthy());
127+
}
113128
}

0 commit comments

Comments
 (0)