Skip to content

Commit d23c438

Browse files
committed
fix: kill the lambda container if we get a ReadFailedException exception
1 parent 232ca72 commit d23c438

3 files changed

Lines changed: 83 additions & 0 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of Ymir PHP Runtime.
7+
*
8+
* (c) Carl Alexander <support@ymirapp.com>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Ymir\Runtime\Lambda\Response;
15+
16+
/**
17+
* A Lambda response for a 502 HTTP response.
18+
*/
19+
class BadGatewayHttpResponse extends AbstractErrorHttpResponse
20+
{
21+
/**
22+
* Constructor.
23+
*/
24+
public function __construct(string $message = 'Bad Gateway', string $templatesDirectory = '')
25+
{
26+
parent::__construct($message, 502, $templatesDirectory);
27+
}
28+
}

src/Runtime.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use AsyncAws\Ssm\Input\GetParametersByPathRequest;
1818
use AsyncAws\Ssm\SsmClient;
1919
use AsyncAws\Ssm\ValueObject\Parameter;
20+
use hollodotme\FastCGI\Exceptions\ReadFailedException;
2021
use Tightenco\Collect\Support\Arr;
2122
use Ymir\Runtime\FastCgi\PhpFpmProcess;
2223
use Ymir\Runtime\Lambda\Handler\BedrockLambdaEventHandler;
@@ -28,6 +29,7 @@
2829
use Ymir\Runtime\Lambda\Handler\RadicleLambdaEventHandler;
2930
use Ymir\Runtime\Lambda\Handler\WarmUpEventHandler;
3031
use Ymir\Runtime\Lambda\Handler\WordPressLambdaEventHandler;
32+
use Ymir\Runtime\Lambda\Response\BadGatewayHttpResponse;
3133
use Ymir\Runtime\Lambda\RuntimeApiClient;
3234

3335
/**
@@ -175,6 +177,13 @@ public function processNextEvent(): void
175177
$this->client->sendResponse($event, $this->handler->handle($event));
176178

177179
++$this->invocations;
180+
} catch (ReadFailedException $exception) {
181+
$this->logger->exception($exception);
182+
183+
$this->client->sendResponse($event, new BadGatewayHttpResponse('The process handling the request crashed unexpectedly'));
184+
185+
$this->logger->info('Killing Lambda container. PHP-FPM process has crashed.');
186+
$this->terminate(1);
178187
} catch (\Throwable $exception) {
179188
$this->logger->exception($exception);
180189
$this->client->sendEventError($event, $exception);

tests/Unit/RuntimeTest.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313

1414
namespace Ymir\Runtime\Tests\Unit;
1515

16+
use hollodotme\FastCGI\Exceptions\ReadFailedException;
1617
use PHPUnit\Framework\TestCase;
18+
use Ymir\Runtime\Lambda\Response\BadGatewayHttpResponse;
1719
use Ymir\Runtime\Runtime;
1820
use Ymir\Runtime\Tests\Mock\InvocationEventInterfaceMockTrait;
1921
use Ymir\Runtime\Tests\Mock\LambdaEventHandlerInterfaceMockTrait;
@@ -77,6 +79,50 @@ public function testProcessNextEvent()
7779
$runtime->processNextEvent();
7880
}
7981

82+
public function testProcessNextEventWithReadFailedException()
83+
{
84+
$client = $this->getLambdaRuntimeApiClientMock();
85+
$event = $this->getInvocationEventInterfaceMock();
86+
$handler = $this->getLambdaEventHandlerInterfaceMock();
87+
$logger = $this->getLoggerMock();
88+
$process = $this->getPhpFpmProcessMock();
89+
90+
$runtime = $this->getMockBuilder(Runtime::class)
91+
->setConstructorArgs([$client, $handler, $logger, $process])
92+
->setMethods(['terminate'])
93+
->getMock();
94+
95+
$client->expects($this->once())
96+
->method('getNextEvent')
97+
->willReturn($event);
98+
99+
$handler->expects($this->once())
100+
->method('canHandle')
101+
->with($this->identicalTo($event))
102+
->willReturn(true);
103+
$handler->expects($this->once())
104+
->method('handle')
105+
->with($this->identicalTo($event))
106+
->willThrowException(new ReadFailedException());
107+
108+
$logger->expects($this->once())
109+
->method('exception')
110+
->with($this->isInstanceOf(ReadFailedException::class));
111+
$logger->expects($this->once())
112+
->method('info')
113+
->with('Killing Lambda container. PHP-FPM process has crashed.');
114+
115+
$client->expects($this->once())
116+
->method('sendResponse')
117+
->with($this->identicalTo($event), $this->isInstanceOf(BadGatewayHttpResponse::class));
118+
119+
$runtime->expects($this->once())
120+
->method('terminate')
121+
->with(1);
122+
123+
$runtime->processNextEvent();
124+
}
125+
80126
public function testStartWithNoException()
81127
{
82128
$client = $this->getLambdaRuntimeApiClientMock();

0 commit comments

Comments
 (0)