Skip to content

Commit

Permalink
Merge pull request #299 from mnapoli/new-runtimes
Browse files Browse the repository at this point in the history
Update runtimes by adding more extensions and fixing stuff
  • Loading branch information
mnapoli authored Apr 6, 2019
2 parents e8f31ea + 94fd0f1 commit dfbf327
Show file tree
Hide file tree
Showing 16 changed files with 201 additions and 91 deletions.
3 changes: 3 additions & 0 deletions docs/environment/php.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Bref strives to include the most common PHP extensions. If a major PHP extension
<td align="left" valign="top">
<ul>
<li>Core</li>
<li><a href="http://php.net/manual/en/book.bc.php">bcmath</a></li>
<li><a href="http://php.net/manual/en/intro.ctype.php">ctype</a></li>
<li><a href="http://php.net/manual/en/book.curl.php">curl</a></li>
<li>date</li>
Expand All @@ -66,6 +67,7 @@ Bref strives to include the most common PHP extensions. If a major PHP extension
<ul>
<li><a href="http://php.net/manual/en/book.libxml.php">libxml</a></li>
<li><a href="http://php.net/manual/en/book.mbstring.php">mbstring</a></li>
<li><a href="http://php.net/manual/en/book.mysqli.php">mysqli</a></li>
<li><a href="http://php.net/manual/en/book.mysqlnd.php">mysqlnd</a></li>
<li><a href="http://php.net/manual/en/book.opcache.php">opcache</a></li>
<li><a href="http://php.net/manual/en/book.openssl.php">openssl</a></li>
Expand All @@ -84,6 +86,7 @@ Bref strives to include the most common PHP extensions. If a major PHP extension
<li><a href="http://php.net/manual/en/book.session.php">session</a></li>
<li><a href="http://php.net/manual/en/book.SimpleXML.php">SimpleXML</a></li>
<li><a href="http://php.net/manual/en/book.sodium.php">sodium</a></li>
<li><a href="http://php.net/manual/en/book.soap.php">SOAP</a></li>
<li><a href="http://php.net/manual/en/book.SPL.php">SPL</a></li>
<li><a href="http://php.net/manual/en/book.sqlite3.php">sqlite3</a></li>
<li><a href="http://php.net/manual/en/book.standard.php">standard</a></li>
Expand Down
6 changes: 3 additions & 3 deletions docs/frameworks/laravel.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Resources:
Timeout: 30 # in seconds (API Gateway has a timeout of 30 seconds)
Runtime: provided
Layers:
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-72-fpm:1'
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-72-fpm:4'
Events:
# The function will match all HTTP URLs
HttpRoot:
Expand All @@ -62,9 +62,9 @@ Resources:
Runtime: provided
Layers:
# PHP runtime
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-72:1'
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-72:4'
# Console layer
- 'arn:aws:lambda:us-east-1:209497400698:layer:console:1'
- 'arn:aws:lambda:us-east-1:209497400698:layer:console:4'

Outputs:
DemoHttpApi:
Expand Down
6 changes: 3 additions & 3 deletions docs/frameworks/symfony.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Resources:
MemorySize: 1024
Runtime: provided
Layers:
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-73-fpm:1'
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-73-fpm:4'
Events:
HttpRoot:
Type: Api
Expand All @@ -61,8 +61,8 @@ Resources:
Timeout: 120 # in seconds
Runtime: provided
Layers:
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-73:1' # PHP
- 'arn:aws:lambda:us-east-1:209497400698:layer:console:1' # The "console" layer
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-73:4' # PHP
- 'arn:aws:lambda:us-east-1:209497400698:layer:console:4' # The "console" layer

Outputs:
DemoApi:
Expand Down
7 changes: 7 additions & 0 deletions runtime/php/layers/fpm/php.ini
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ opcache.max_accelerated_files=10000

zend_extension=opcache.so

; This directive determines which super global arrays are registered when PHP
; starts up. G,P,C,E & S are abbreviations for the following respective super
; globals: GET, POST, COOKIE, ENV and SERVER.
; We explicitly populate all variables else ENV is not populated by default.
; See https://github.com/mnapoli/bref/pull/291
variables_order="EGPCS"

; The lambda environment is not compatible with fastcgi_finish_request
; See https://github.com/mnapoli/bref/issues/214
disable_functions=fastcgi_finish_request
7 changes: 7 additions & 0 deletions runtime/php/layers/function/php.ini
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,10 @@ opcache.memory_consumption=128
opcache.max_accelerated_files=10000

zend_extension=opcache.so

; This directive determines which super global arrays are registered when PHP
; starts up. G,P,C,E & S are abbreviations for the following respective super
; globals: GET, POST, COOKIE, ENV and SERVER.
; We explicitly populate all variables else ENV is not populated by default.
; See https://github.com/mnapoli/bref/pull/291
variables_order="EGPCS"
2 changes: 2 additions & 0 deletions runtime/php/php.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -408,8 +408,10 @@ RUN set -xe \
--with-gettext \
--enable-mbstring \
--with-pdo-mysql=shared,mysqlnd \
--with-mysqli \
--enable-pcntl \
--enable-zip \
--enable-bcmath \
--with-pdo-pgsql=shared,${INSTALL_DIR} \
--enable-intl=shared \
--enable-opcache-file \
Expand Down
104 changes: 69 additions & 35 deletions src/Runtime/LambdaRuntime.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
*/
class LambdaRuntime
{
/** @var resource|null */
private $handler;

/** @var resource|null */
private $returnHandler;

/** @var string */
private $apiUrl;

Expand All @@ -39,6 +45,27 @@ public function __construct(string $apiUrl)
$this->apiUrl = $apiUrl;
}

public function __destruct()
{
$this->closeHandler();
$this->closeReturnHandler();
}

private function closeHandler(): void
{
if ($this->handler !== null) {
curl_close($this->handler);
$this->handler = null;
}
}
private function closeReturnHandler(): void
{
if ($this->returnHandler !== null) {
curl_close($this->returnHandler);
$this->returnHandler = null;
}
}

/**
* Process the next event.
*
Expand Down Expand Up @@ -70,13 +97,15 @@ public function processNextEvent(callable $handler): void
*/
private function waitNextInvocation(): array
{
$handler = curl_init("http://{$this->apiUrl}/2018-06-01/runtime/invocation/next");
curl_setopt($handler, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($handler, CURLOPT_FAILONERROR, true);
if ($this->handler === null) {
$this->handler = curl_init("http://{$this->apiUrl}/2018-06-01/runtime/invocation/next");
curl_setopt($this->handler, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($this->handler, CURLOPT_FAILONERROR, true);
}

// Retrieve invocation ID
$invocationId = '';
curl_setopt($handler, CURLOPT_HEADERFUNCTION, function ($ch, $header) use (&$invocationId) {
curl_setopt($this->handler, CURLOPT_HEADERFUNCTION, function ($ch, $header) use (&$invocationId) {
if (! preg_match('/:\s*/', $header)) {
return strlen($header);
}
Expand All @@ -90,23 +119,24 @@ private function waitNextInvocation(): array

// Retrieve body
$body = '';
curl_setopt($handler, CURLOPT_WRITEFUNCTION, function ($ch, $chunk) use (&$body) {
curl_setopt($this->handler, CURLOPT_WRITEFUNCTION, function ($ch, $chunk) use (&$body) {
$body .= $chunk;

return strlen($chunk);
});

curl_exec($handler);
if (curl_error($handler)) {
throw new \Exception('Failed to fetch next Lambda invocation: ' . curl_error($handler));
curl_exec($this->handler);
if (curl_errno($this->handler) > 0) {
$message = curl_error($this->handler);
$this->closeHandler();
throw new \Exception('Failed to fetch next Lambda invocation: ' . $message);
}
if ($invocationId === '') {
throw new \Exception('Failed to determine the Lambda invocation ID');
}
if ($body === '') {
throw new \Exception('Empty Lambda runtime API response');
}
curl_close($handler);

$event = json_decode($body, true);

Expand Down Expand Up @@ -160,27 +190,28 @@ private function signalFailure(string $invocationId, \Throwable $error): void
*/
public function failInitialization(string $message, ?\Throwable $error = null): void
{
if ($error instanceof \Exception) {
$errorMessage = get_class($error) . ': ' . $error->getMessage();
} else {
$errorMessage = $error->getMessage();
}

// Log the exception in CloudWatch
echo "$message\n";
printf(
"Fatal error: %s in %s:%d\nStack trace:\n%s",
$errorMessage,
$error->getFile(),
$error->getLine(),
$error->getTraceAsString()
);
if ($error) {
if ($error instanceof \Exception) {
$errorMessage = get_class($error) . ': ' . $error->getMessage();
} else {
$errorMessage = $error->getMessage();
}
printf(
"Fatal error: %s in %s:%d\nStack trace:\n%s",
$errorMessage,
$error->getFile(),
$error->getLine(),
$error->getTraceAsString()
);
}

$url = "http://{$this->apiUrl}/2018-06-01/runtime/init/error";
$this->postJson($url, [
'errorMessage' => $message . ' ' . $error->getMessage(),
'errorType' => get_class($error),
'stackTrace' => explode(PHP_EOL, $error->getTraceAsString()),
'errorType' => $error ? get_class($error) : 'Internal',
'stackTrace' => $error ? explode(PHP_EOL, $error->getTraceAsString()) : [],
]);

exit(1);
Expand All @@ -196,21 +227,24 @@ private function postJson(string $url, $data): void
throw new \Exception('Failed encoding Lambda JSON response: ' . json_last_error_msg());
}

$handler = curl_init($url);
curl_setopt($handler, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($handler, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handler, CURLOPT_FAILONERROR, true);
curl_setopt($handler, CURLOPT_POSTFIELDS, $jsonData);
curl_setopt($handler, CURLOPT_HTTPHEADER, [
if ($this->returnHandler === null) {
$this->returnHandler = curl_init();
curl_setopt($this->returnHandler, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($this->returnHandler, CURLOPT_RETURNTRANSFER, true);
curl_setopt($this->returnHandler, CURLOPT_FAILONERROR, true);
}

curl_setopt($this->returnHandler, CURLOPT_URL, $url);
curl_setopt($this->returnHandler, CURLOPT_POSTFIELDS, $jsonData);
curl_setopt($this->returnHandler, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Content-Length: ' . strlen($jsonData),
]);
curl_exec($handler);
if (curl_error($handler)) {
$errorMessage = curl_error($handler);
curl_close($handler);
curl_exec($this->returnHandler);
if (curl_errno($this->returnHandler) > 0) {
$errorMessage = curl_error($this->returnHandler);
$this->closeReturnHandler();
throw new \Exception('Error while calling the Lambda runtime API: ' . $errorMessage);
}
curl_close($handler);
}
}
8 changes: 4 additions & 4 deletions template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Resources:
Handler: demo/function.php
Runtime: provided
Layers:
- 'arn:aws:lambda:us-east-2:209497400698:layer:php-72:3'
- 'arn:aws:lambda:us-east-2:209497400698:layer:php-72:4'

HttpFunction:
Type: AWS::Serverless::Function
Expand All @@ -29,7 +29,7 @@ Resources:
MemorySize: 1024 # The memory size is related to the pricing and CPU power
Runtime: provided
Layers:
- 'arn:aws:lambda:us-east-2:209497400698:layer:php-72-fpm:3'
- 'arn:aws:lambda:us-east-2:209497400698:layer:php-72-fpm:4'
Events:
HttpRoot:
Type: Api
Expand All @@ -51,8 +51,8 @@ Resources:
Handler: demo/console.php
Runtime: provided
Layers:
- 'arn:aws:lambda:us-east-2:209497400698:layer:php-72:3'
- 'arn:aws:lambda:us-east-2:209497400698:layer:console:3'
- 'arn:aws:lambda:us-east-2:209497400698:layer:php-72:4'
- 'arn:aws:lambda:us-east-2:209497400698:layer:console:4'

Outputs:
DemoHttpApi:
Expand Down
4 changes: 2 additions & 2 deletions template/console/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ Resources:
MemorySize: 1024 # The memory size is related to the pricing and CPU power
Runtime: provided
Layers:
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-73:1' # PHP
- 'arn:aws:lambda:us-east-1:209497400698:layer:console:1' # The "console" layer
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-73:4' # PHP
- 'arn:aws:lambda:us-east-1:209497400698:layer:console:4' # The "console" layer
2 changes: 1 addition & 1 deletion template/default/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ Resources:
MemorySize: 1024 # The memory size is related to the pricing and CPU power
Runtime: provided
Layers:
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-73:1'
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-73:4'
2 changes: 1 addition & 1 deletion template/http/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Resources:
MemorySize: 1024 # The memory size is related to the pricing and CPU power
Runtime: provided
Layers:
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-73-fpm:1'
- 'arn:aws:lambda:us-east-1:209497400698:layer:php-73-fpm:4'
Events:
# The function will match all HTTP URLs
HttpRoot:
Expand Down
8 changes: 8 additions & 0 deletions tests/Sam/Php/function.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@
return ini_get_all(null, false);
}

if ($event['env'] ?? false) {
return [
'$_ENV' => $_ENV['FOO'] ?? null,
'$_SERVER' => $_SERVER['FOO'] ?? null,
'getenv' => getenv('FOO'),
];
}

if ($event['stdout'] ?? false) {
echo 'This is a test log by writing to stdout';
}
Expand Down
10 changes: 10 additions & 0 deletions tests/Sam/PhpFpm/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@
return;
}

if ($_GET['env'] ?? false) {
header('Content-Type: application/json');
echo json_encode([
'$_ENV' => $_ENV['FOO'] ?? null,
'$_SERVER' => $_SERVER['FOO'] ?? null,
'getenv' => getenv('FOO'),
], JSON_PRETTY_PRINT);
return;
}

if ($_GET['stderr'] ?? false) {
$stderr = fopen('php://stderr', 'a');
fwrite($stderr, 'This is a test log into stderr');
Expand Down
Loading

0 comments on commit dfbf327

Please sign in to comment.