Skip to content

Commit 58976fd

Browse files
authored
Merge pull request #23 from xp-forge/feature/streaming
Implement streaming lambda responses
2 parents 08c531f + 5ac4378 commit 58976fd

22 files changed

+907
-173
lines changed

README.md

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use com\amazon\aws\lambda\Handler;
1919

2020
class Greet extends Handler {
2121

22-
/** @return com.amazon.aws.lambda.Lambda|callable */
22+
/** @return callable|com.amazon.aws.lambda.Lambda|com.amazon.aws.lambda.Streaming */
2323
public function target() {
2424
return fn($event, $context) => sprintf(
2525
'Hello %s from PHP %s via %s @ %s',
@@ -43,7 +43,7 @@ use com\amazon\aws\lambda\Handler;
4343

4444
class Greet extends Handler {
4545

46-
/** @return com.amazon.aws.lambda.Lambda|callable */
46+
/** @return callable|com.amazon.aws.lambda.Lambda|com.amazon.aws.lambda.Streaming */
4747
public function target() {
4848
$default= $this->environment->properties('task')->readString('greet', 'default');
4949

@@ -60,7 +60,6 @@ class Greet extends Handler {
6060

6161
The lambda's environment accessible via *$this->environment* is an Environment instance, see [below](https://github.com/xp-forge/lambda#environment).
6262

63-
6463
### Logging
6564

6665
To write output to the lambda's log stream, use *trace()*:
@@ -70,7 +69,7 @@ use com\amazon\aws\lambda\Handler;
7069

7170
class Greet extends Handler {
7271

73-
/** @return com.amazon.aws.lambda.Lambda|callable */
72+
/** @return callable|com.amazon.aws.lambda.Lambda|com.amazon.aws.lambda.Streaming */
7473
public function target() {
7574
return function($event, $context) {
7675
$this->environment->trace('Invoked with ', $event);
@@ -83,6 +82,33 @@ class Greet extends Handler {
8382

8483
Any non-string arguments passed will be converted to string using `util.Objects::stringOf()`. To integrate with [XP logging](https://github.com/xp-framework/logging), pass the environment's writer to the console appender, e.g. by using `$cat= Logging::all()->toConsole($this->environment->writer)`.
8584

85+
### Response streaming
86+
87+
This library supports AWS Lambda response streaming as [announced by AWS in April 2023](https://aws.amazon.com/de/blogs/compute/introducing-aws-lambda-response-streaming/). To use the stream, return a `function(var, Stream, Context)` from the handler's *target()* method instead of a `function(var, Context)`:
88+
89+
```php
90+
use com\amazon\aws\lambda\{Context, Handler, Stream};
91+
92+
class Streamed extends Handler {
93+
94+
public function target(): callable {
95+
return function($event, Stream $stream, Context $context) {
96+
$stream->use('text/plain');
97+
$stream->write("[".date('r')."] Hello world...\n");
98+
99+
sleep(1);
100+
101+
$stream->write("[".date('r')."] ...from Lambda\n");
102+
$stream->end();
103+
};
104+
}
105+
}
106+
```
107+
108+
Invoking this lambda will yield the following:
109+
110+
![Streaming in Terminal](https://github.com/xp-forge/lambda/assets/696742/41785beb-3903-45a0-a2ec-2c7c27c2c7b4)
111+
86112
Development
87113
-----------
88114
To run your lambda locally, use the following:
@@ -206,9 +232,9 @@ In order to programmatically use other AWS services use the *ServiceEndpoint* cl
206232
use com\amazon\aws\{Credentials, ServiceEndpoint};
207233
use com\amazon\aws\lambda\Handler;
208234

209-
class Streaming extends Handler {
235+
class WebSockets extends Handler {
210236

211-
/** @return com.amazon.aws.lambda.Lambda|callable */
237+
/** @return callable|com.amazon.aws.lambda.Lambda|com.amazon.aws.lambda.Streaming */
212238
public function target() {
213239
return function($event, $context) {
214240

@@ -228,7 +254,7 @@ class Streaming extends Handler {
228254
To test this locally, pass the necessary environment variables via *-e* on the command line:
229255

230256
```bash
231-
$ xp lambda test -e AWS_ACCESS_KEY_ID=... -e AWS_SECRET_ACCESS_KEY=... Streaming '{"requestContext":...}'
257+
$ xp lambda test -e AWS_ACCESS_KEY_ID=... -e AWS_SECRET_ACCESS_KEY=... WebSockets '{"requestContext":...}'
232258
# ...
233259
```
234260

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
<?php namespace com\amazon\aws\lambda;
22

3-
use lang\IllegalArgumentException;
4-
53
/**
64
* Base class for lambda handlers. Subclasses overwrite the `target` method,
75
* perform initialization there and finally return the invokeable lambda.
@@ -19,18 +17,6 @@ public function __construct(Environment $environment) {
1917
/** @return com.amazon.aws.lambda.Environment */
2018
public function environment() { return $this->environment; }
2119

22-
/** @return com.amazon.aws.lambda.Lambda|callable */
20+
/** @return com.amazon.aws.lambda.Lambda|com.amazon.aws.lambda.Streaming|callable */
2321
public abstract function target();
24-
25-
/** @return callable */
26-
public final function lambda() {
27-
$target= $this->target();
28-
if ($target instanceof Lambda) {
29-
return [$target, 'process'];
30-
} else if (is_callable($target)) {
31-
return $target;
32-
} else {
33-
throw new IllegalArgumentException('Expected either a callable or a Lambda instance, have '.typeof($target));
34-
}
35-
}
3622
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php namespace com\amazon\aws\lambda;
2+
3+
use lang\Value;
4+
use util\Comparison;
5+
6+
/** @see https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html#runtimes-custom-response-streaming */
7+
abstract class InvokeMode implements Value {
8+
use Comparison;
9+
10+
protected $api, $identifier;
11+
12+
/** Creates a new invoke mode instance */
13+
public function __construct(RuntimeApi $api, $identifier) {
14+
$this->api= $api;
15+
$this->identifier= $identifier;
16+
}
17+
18+
/**
19+
* Invokes the given lambda
20+
*
21+
* @param callable $lambda
22+
* @param var $event
23+
* @param com.amazon.aws.lambda.Context $context
24+
* @return peer.HttpResponse
25+
*/
26+
public abstract function invoke($lambda, $event, $context);
27+
28+
/** @return string */
29+
public function toString() {
30+
return strtr(self::class, '\\', '.').'<'.$this->identifier.'>';
31+
}
32+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php namespace com\amazon\aws\lambda;
2+
3+
class Invokeable {
4+
public $callable, $mode;
5+
6+
/**
7+
* Create a new invokeable
8+
*
9+
* @param callable $callable
10+
* @param com.amazon.aws.lambda.InvokeMode $mode
11+
*/
12+
public function __construct($callable, InvokeMode $mode) {
13+
$this->callable= $callable;
14+
$this->mode= $mode;
15+
}
16+
17+
/**
18+
* Invoke this instance
19+
*
20+
* @param var $event
21+
* @param com.amazon.aws.lambda.Context $context
22+
* @return var
23+
*/
24+
public function invoke($event, Context $context) {
25+
return $this->mode->invoke($this->callable, $event, $context);
26+
}
27+
}

0 commit comments

Comments
 (0)