Swoole will be shipping something really-really cool that is it's own CLI. You can start playing with it using the pre-compiled binary distributed under Swoole's releases at https://github.com/swoole/swoole-src/releases/tag/v4.8.7.
The trick here, for this project, is: we will be shipping Swoole CLI binary along side with Bref's LambdaRuntime
to provide a custom AWS lambda runtime that is Swoole powered.
Let's get started.
Create a directory to hold our files:
mkdir swoole-lambda
cd swoole-lambda
Bring Swoole's IDE helper so we can have code completions in our editor:
composer require --dev swoole/ide-helper
Then we can already bring Bref to the playground:
composer require bref/bref
Bref will provide us the abstraction to communicate with AWS Lambda runtime. We can just call it at our bootstrap file. The bootstrap file is where the lambda runtime will start the invocation:
#!/opt/bin/swoole-cli
<?php
use Bref\Context\Context;
use Bref\Runtime\LambdaRuntime;
use Swoole\Coroutine;
require_once __DIR__ . '/vendor/autoload.php';
$runtime = LambdaRuntime::fromEnvironmentVariable('swoole-cli');
$handler = require $_ENV['LAMBDA_TASK_ROOT'] . '/handler.php';
Coroutine\run(static function () use ($runtime, $handler): void {
while (true) {
$runtime->processNextEvent($handler);
}
});
AWS Lambda will move what is in our bin/
directory to /opt/bin
, so our Swoole CLI will be there. That is why we can create our Bootstrap PHP application as a self-executing script that will be using an interpreter located at that path.
Let's grab it:
wget https://github.com/swoole/swoole-src/releases/download/v4.8.7/swoole-cli-v4.8.7-linux-x64.tar.xz
tar -xf swoole-cli-v4.8.7-linux-x64.tar.xz
mkdir bin
mv swoole-cli bin/
rm swoole-cli-v4.8.7-linux-x64.tar.xz
UPX to the rescue! 148MB can be too large for a function. Let's use UPX to make it smaller:
upx -9 bin/swoole-cli
The -9
tells UPX to make it as small as possible. This can take a while, but the final result is a 44MB binary, it is about 30% of the original file size!
Now we can safely create our runtime ZIP file:
zip -r runtime.zip bootstrap bin
And upload it to AWS Lambda as a layer:
aws lambda publish-layer-version \
--layer-name swoole-runtime \
--zip-file fileb://runtime.zip \
--region us-east-1
Now lets zip our vendor files:
zip -r vendor.zip vendor
And upload it as a layer as well:
aws lambda publish-layer-version \
--layer-name swoole-lambda-vendor \
--zip-file fileb://vendor.zip \
--region us-east-1
With the layers uploaded, we are ready to create our function.
The handler.php
file which bootstrap
requires, holds our function code:
<?php
declare(strict_types=1);
use Bref\Context\Context;
return static fn ($event, Context $context): string =>
'Hello ' . ($event['name'] ?? 'world');
Zip it:
zip -r function.zip handler.php
And create:
aws lambda create-function \
--function-name swoole-lambda \
--handler handler.handler \
--zip-file fileb://function.zip \
--runtime provided \
--role arn:aws:iam::884320951759:role/swoole-lambda \
--region us-east-1 \
--layers arn:aws:lambda:us-east-1:884320951759:layer:swoole-runtime:1 \
arn:aws:lambda:us-east-1:884320951759:layer:swoole-lambda-vendor:1
Ok, roll the drums.
Let's test it:
aws lambda invoke \
--function-name swoole-lambda \
--region us-east-1 \
--log-type Tail \
--query 'LogResult' \
--output text \
--payload $(echo '{"name": "Swoole"}' | base64) output.txt | base64 --decode
The output should be something like:
START RequestId: eaa39e02-b833-4f06-b18d-7e9a5b603a97 Version: $LATEST
END RequestId: eaa39e02-b833-4f06-b18d-7e9a5b603a97
REPORT RequestId: eaa39e02-b833-4f06-b18d-7e9a5b603a97 Duration: 3.67 ms Billed Duration: 4 ms Memory Size: 128 MB Max Memory Used: 115 MB
Let's see the results:
cat output.txt
"Hello Swoole"
That is all folks!
Bref abstracts way all the hassle about interfacing with AWS Lambda runtime. Internally it uses curl_*
which Swoole can hook up and make asynchronously!
And of course, don't need to mention, the Swoole CLI project also rocks a lot bringing us a PHP interpreter with Swoole built-in (statically compiled).
Top comments (3)
Great read, very well explained!
Great article!