xp-forge / lambda
XP框架的AWS Lambda
Requires
- php: >=7.0.0
- xp-forge/aws: ^2.0 | ^1.0
- xp-forge/json: ^5.0 | ^4.0
- xp-framework/core: ^12.0 | ^11.0 | ^10.14
- xp-framework/http: ^10.0 | ^9.0
- xp-framework/zip: ^11.0 | ^10.0 | ^9.0
Requires (Dev)
- xp-framework/test: ^2.0 | ^1.0
This package is auto-updated.
Last update: 2024-09-17 18:33:26 UTC
README
无服务器基础设施。
示例
将此代码放入名为 Greet.class.php 的文件中
use com\amazon\aws\lambda\Handler; class Greet extends Handler { /** @return callable|com.amazon.aws.lambda.Lambda|com.amazon.aws.lambda.Streaming */ public function target() { return fn($event, $context) => sprintf( 'Hello %s from PHP %s via %s @ %s', $event['name'], PHP_VERSION, $context->functionName, $context->region ); } }
传递的两个参数是 $event(一个值,取决于lambda从哪里被调用)和 $context(一个上下文实例,见下文)。
初始化
如果您需要运行任何初始化代码,可以在从 target() 返回lambda之前执行。这段代码仅在初始化阶段运行一次。
use com\amazon\aws\lambda\Handler; class Greet extends Handler { /** @return callable|com.amazon.aws.lambda.Lambda|com.amazon.aws.lambda.Streaming */ public function target() { $default= $this->environment->properties('task')->readString('greet', 'default'); return fn($event, $context) => sprintf( 'Hello %s from PHP %s via %s @ %s', $event['name'] ?? $default, PHP_VERSION, $context->functionName, $context->region ); } }
通过 $this->environment 访问的lambda的环境是一个环境实例,见下文。
日志记录
要向lambda的日志流写入输出,请使用 trace()
use com\amazon\aws\lambda\Handler; class Greet extends Handler { /** @return callable|com.amazon.aws.lambda.Lambda|com.amazon.aws.lambda.Streaming */ public function target() { return function($event, $context) { $this->environment->trace('Invoked with ', $event); return sprintf(/* Shortened for brevity */); }; } }
任何非字符串参数都会使用 util.Objects::stringOf()
转换为字符串。要集成到XP日志,将环境的writer传递给控制台追加器,例如使用 $cat= Logging::all()->toConsole($this->environment->writer)
。
响应流
此库支持AWS Lambda响应流,这是AWS在2023年4月宣布的功能。要使用流,请从处理器的方法 target() 返回一个 function(var, Stream, Context)
,而不是一个 function(var, Context)
。
use com\amazon\aws\lambda\{Context, Handler, Stream}; class Streamed extends Handler { public function target(): callable { return function($event, Stream $stream, Context $context) { $stream->use('text/plain'); $stream->write("[".date('r')."] Hello world...\n"); sleep(1); $stream->write("[".date('r')."] ...from Lambda\n"); $stream->end(); }; } }
调用此lambda将产生以下结果
Stream 接口定义如下
public interface com.amazon.aws.lambda.Stream extends io.streams.OutputStream, lang.Closeable { public function transmit(io.Channel|io.streams.InputStream $source, string $mimeType): void public function use(string $mimeType): void public function write(string $bytes): void public function end(): void public function flush(): void public function close(): var }
开发
要本地运行lambda,请使用以下命令
$ xp lambda run Greet '{"name":"Timm"}'
Hello Timm from PHP 8.2.11 via Greet @ test-local-1
这不会提供完整的lambda环境,并且没有执行限制!要程序化地检测此环境,请使用 $this->environment->local()
,它将返回true。
集成测试
要测试在本地容器化lambda环境中运行的lambda,请使用 test 命令。
$ xp lambda test Greet '{"name":"Timm"}' START RequestId: 9ff45cda-df9b-1b8c-c21b-5fe27c8f2d24 Version: $LATEST END RequestId: 9ff45cda-df9b-1b8c-c21b-5fe27c8f2d24 REPORT RequestId: 9ff45cda-df9b-1b8c-c21b-5fe27c8f2d24 Init Duration: 922.19 ms... "Hello Timm from PHP 8.2.11 via test @ us-east-1"
此功能由AWS Lambda自定义运行时基础镜像提供。虽然它也在您的机器上运行,但 $this->environment->local()
将返回false。
设置
第一步是创建和发布运行时层
$ xp lambda runtime $ aws lambda publish-layer-version \ --layer-name lambda-xp-runtime \ --zip-file fileb://./runtime-X.X.X.zip \ --region us-east-1
...并创建一个角色
$ cat > /tmp/trust-policy.json { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole" }] } $ aws iam create-role \ --role-name InvokeLambda \ --path "/service-role/" \ --assume-role-policy-document file:///tmp/trust-policy.json
在确保使用composer更新了依赖项后,创建函数
$ xp lambda package Greet.class.php $ aws lambda create-function \ --function-name greet \ --handler Greet \ --zip-file fileb://./function.zip \ --runtime provided.al2 \ --role "arn:aws:iam::XXXXXXXXXXXX:role/service-role/InvokeLambda" \ --region us-east-1 \ --layers "arn:aws:lambda:us-east-1:XXXXXXXXXXXX:layer:lambda-xp-runtime:1"
调用
要调用函数
$ aws lambda invoke \ --cli-binary-format raw-in-base64-out \ --function-name greet \ --payload '{"name":"Timm"}' response.json $ cat response.json "Hello Timm from PHP 8.0.10 via greet @ us-east-1"
部署更改
在最初创建lambda之后,您可以更新其代码如下
$ xp lambda package Greet.class.php $ aws lambda update-function-code \ --function-name greet \ --zip-file fileb://./function.zip \ --publish
升级运行时
要升级现有的运行时层,构建新的运行时并发布新版本,请调用以下命令以创建新版本
$ xp lambda runtime $ aws lambda publish-layer-version \ --layer-name lambda-xp-runtime \ --zip-file fileb://./runtime-X.X.X.zip \ --region us-east-1
现在,切换函数以使用此新层
$ aws lambda update-function-configuration \
--function-name greet \
--layers "arn:aws:lambda:us-east-1:XXXXXXXXXXXX:layer:lambda-xp-runtime:2"
使用其他AWS服务
要程序化地使用其他AWS服务,请使用 ServiceEndpoint 类
use com\amazon\aws\{Credentials, ServiceEndpoint}; use com\amazon\aws\lambda\Handler; class WebSockets extends Handler { /** @return callable|com.amazon.aws.lambda.Lambda|com.amazon.aws.lambda.Streaming */ public function target() { return function($event, $context) { // Send message to WebSocket connection $this->environment->endpoint('execute-api') ->in($context->region) ->using($event['requestContext']['apiId']) ->resource('/{stage}/@connections/{connectionId}', $event['requestContext']) ->transmit(['message' => 'Reply']) ; return ['statusCode' => 200]; }; } }
要本地测试此功能,请通过命令行的 -e 传递必要的环境变量
$ xp lambda test -e AWS_ACCESS_KEY_ID=... -e AWS_SECRET_ACCESS_KEY=... WebSockets '{"requestContext":...}' # ...
上下文
传递给目标lambda的上下文对象定义如下
public class com.amazon.aws.lambda.Context implements lang.Value { public string $awsRequestId public string $invokedFunctionArn public string $traceId public string $clientContext public string $cognitoIdentity public string $deadline public string $functionName public string $functionVersion public string $memoryLimitInMB public string $logGroupName public string $logStreamName public string $region public int $payloadLength public function __construct(array $headers, array $environment) public function remainingTime(?float $now): ?float public function toString(): string public function hashCode(): string public function compareTo(var $value): int }
环境
运行时环境定义如下
public class com.amazon.aws.lambda.Environment { public string $root public [:string] $variables public io.streams.StringWriter $writer public util.PropertySource $properties public function __construct(string $root, ?io.streams.StringWriter $writer) public function taskroot(): io.Path public function path(string $path): io.Path public function tempDir(): io.Path public function local(): bool public function variable(string $name): ?string public function credentials(): com.amazon.aws.Credentials public function trace(var... $args): void public function properties(string $name): util.PropertyAccess }
接口
除了函数外,处理器的 target() 方法还可以返回实现 Lambda 或 Streaming 接口的实例
public interface com.amazon.aws.lambda.Lambda { public function process(var $event, com.amazon.aws.lambda.Context $context): var } public interface com.amazon.aws.lambda.Streaming { public function handle( var $event, com.amazon.aws.lambda.Stream $stream, com.amazon.aws.lambda.Context $context ): void }