Add notes on AWS platform-specific features

This commit is contained in:
Dave Syer
2018-06-04 14:00:26 +01:00
parent fee3a0bec3
commit 1fd83527a7
3 changed files with 111 additions and 93 deletions

View File

@@ -2,4 +2,22 @@ The https://aws.amazon.com/[AWS] adapter takes a Spring Cloud Function app and c
== Introduction
include::aws-intro.adoc[]
include::aws-intro.adoc[]
== Platfom Specific Features
=== HTTP and API Gateway
AWS has some platform-specific data types, including batching of messages, which is much more efficient than processing each one individually. To make use of these types you can write a function that depends on those types. Or you can rely on Spring to extract the data from the AWS types and convert it to a Spring `Message`. To do this you tell AWS that the function is of a specific generic handler type (depending on the AWS service) and provide a bean of type `Function<Message<S>,Message<T>>`, where `S` and `T` are your business data types. If there is more than one bean of type `Function` you may also need to configure the Spring Boot property `function.name` to be the name of the target bean (e.g. use `FUNCTION_NAME` as an environment variable).
The supported AWS services and generic handler types are listed below:
|===
| Service | AWS Types | Generic Handler |
| API Gateway | `APIGatewayProxyRequestEvent`, `APIGatewayProxyResponseEvent` | `org.springframework.cloud.function.adapter.aws.SpringBootApiGatewayRequestHandler` |
| Kinesis | KinesisEvent | org.springframework.cloud.function.adapter.aws.SpringBootKinesisEventHandler |
|===
For example, to deploy behind an API Gateway, use `--handler org.springframework.cloud.function.adapter.aws.SpringBootApiGatewayRequestHandler` in your AWS command line (in via the UI) and define a `@Bean` of type `Function<Message<Foo>,Message<Bar>>` where `Foo` and `Bar` are POJO types (the data will be marshalled and unmarshalled by AWS using Jackson).

View File

@@ -57,95 +57,3 @@ Functions can be grouped together in a single application, or deployed
one-per-jar. It's up to the developer to choose. An app with multiple
functions can be deployed multiple times in different "personalities",
exposing different functions over different physical transports.
== Dynamic Compilation
There is a sample app that uses the function compiler to create a
function from a configuration property. The vanilla "function-sample"
also has that feature. And there are some examples that you can run to
see the compilation happening at run time. To run these examples,
change into the `scripts` directory:
----
cd scripts
----
Also, start a RabbitMQ server locally (e.g. execute `rabbitmq-server`).
=== Start the Function Registry Service:
----
./function-registry.sh
----
=== Register a Function:
----
./registerFunction.sh -n uppercase -f "f->f.map(s->s.toString().toUpperCase())"
----
=== Run a REST Microservice using that Function:
----
./web.sh -f uppercase -p 9000
curl -H "Content-Type: text/plain" -H "Accept: text/plain" localhost:9000/uppercase -d foo
----
=== Register a Supplier:
----
./registerSupplier.sh -n words -f "()->Flux.just(\"foo\",\"bar\")"
----
=== Run a REST Microservice using that Supplier:
----
./web.sh -s words -p 9001
curl -H "Accept: application/json" localhost:9001/words
----
=== Register a Consumer:
----
./registerConsumer.sh -n print -t String -f "System.out::println"
----
=== Run a REST Microservice using that Consumer:
----
./web.sh -c print -p 9002
curl -X POST -H "Content-Type: text/plain" -d foo localhost:9002/print
----
=== Run Stream Processing Microservices:
First register a streaming words supplier:
----
./registerSupplier.sh -n wordstream -f "()->Flux.interval(Duration.ofMillis(1000)).map(i->\"message-\"+i)"
----
Then start the source (supplier), processor (function), and sink (consumer) apps
(in reverse order):
----
./stream.sh -p 9103 -i uppercaseWords -c print
./stream.sh -p 9102 -i words -f uppercase -o uppercaseWords
./stream.sh -p 9101 -s wordstream -o words
----
The output will appear in the console of the sink app (one message per second, converted to uppercase):
----
MESSAGE-0
MESSAGE-1
MESSAGE-2
MESSAGE-3
MESSAGE-4
MESSAGE-5
MESSAGE-6
MESSAGE-7
MESSAGE-8
MESSAGE-9
...
----

View File

@@ -112,6 +112,98 @@ Spring Cloud Function provides a "deployer" library that allows you to launch a
The standard entry point of the API is the Spring configuration annotation `@EnableFunctionDeployer`. If that is used in a Spring Boot application the deployer kicks in and looks for some configuration to tell it where to find the function jar. At a minimum the user has to provide a `function.location` which is a URL or resource location for the archive containing the functions. It can optionally use a `maven:` prefix to locate the artifact via a dependency lookup (see `FunctionProperties` for complete details). A Spring Boot application is bootstrapped from the jar file, using the `MANIFEST.MF` to locate a start class, so that a standard Spring Boot fat jar works well, for example. If the target jar can be launched successfully then the result is a function registered in the main application's `FunctionCatalog`. The registered function can be applied by code in the main application, even though it was created in an isolated class loader (by deault).
== Dynamic Compilation
There is a sample app that uses the function compiler to create a
function from a configuration property. The vanilla "function-sample"
also has that feature. And there are some scripts that you can run to
see the compilation happening at run time. To run these examples,
change into the `scripts` directory:
----
cd scripts
----
Also, start a RabbitMQ server locally (e.g. execute `rabbitmq-server`).
Start the Function Registry Service:
----
./function-registry.sh
----
Register a Function:
----
./registerFunction.sh -n uppercase -f "f->f.map(s->s.toString().toUpperCase())"
----
Run a REST Microservice using that Function:
----
./web.sh -f uppercase -p 9000
curl -H "Content-Type: text/plain" -H "Accept: text/plain" localhost:9000/uppercase -d foo
----
Register a Supplier:
----
./registerSupplier.sh -n words -f "()->Flux.just(\"foo\",\"bar\")"
----
Run a REST Microservice using that Supplier:
----
./web.sh -s words -p 9001
curl -H "Accept: application/json" localhost:9001/words
----
Register a Consumer:
----
./registerConsumer.sh -n print -t String -f "System.out::println"
----
Run a REST Microservice using that Consumer:
----
./web.sh -c print -p 9002
curl -X POST -H "Content-Type: text/plain" -d foo localhost:9002/print
----
Run Stream Processing Microservices:
First register a streaming words supplier:
----
./registerSupplier.sh -n wordstream -f "()->Flux.interval(Duration.ofMillis(1000)).map(i->\"message-\"+i)"
----
Then start the source (supplier), processor (function), and sink (consumer) apps
(in reverse order):
----
./stream.sh -p 9103 -i uppercaseWords -c print
./stream.sh -p 9102 -i words -f uppercase -o uppercaseWords
./stream.sh -p 9101 -s wordstream -o words
----
The output will appear in the console of the sink app (one message per second, converted to uppercase):
----
MESSAGE-0
MESSAGE-1
MESSAGE-2
MESSAGE-3
MESSAGE-4
MESSAGE-5
MESSAGE-6
MESSAGE-7
MESSAGE-8
MESSAGE-9
...
----
== Serverless Platform Adapters
As well as being able to run as a standalone process, a Spring Cloud