Micronaut Severless Function
Micronautには、Serverless Functionを作成するための機能があります。
Springなどとの他のフレームワークに比べての利点は、Micronautはコンパイル時に依存関係を解決する仕組みや、メモリのフットプリントの軽さが売りのようです。
作成したFunctionは、AWS LambdaやOpenFaaSなどにデプロイすることができるようです。
このMicronautのServerless Functionを作成する機能を、簡単に試してみたいと思います。
環境
環境は、こちらです。
$ mn -V
| Micronaut Version: 1.0.4
| JVM Version: 1.8.0_191
プロジェクト作成
--profile
をfunction-aws
として、プロジェクトを作成します。
$ mn create-app --profile function-aws --build maven hello-function
$ cd hello-function
指定できるfunction
のProfileは、function-aws
のみのようなので…。
$ mn list-profiles
| Available Profiles
--------------------
cli The cli profile
federation The federation profile
function-aws The function profile for AWS Lambda
kafka The Kafka messaging profile
profile A profile for creating new Micronaut profiles
service The service profile
単にfunction
とか書いたりすると、「そんなProfileはない」と怒られます。
$ mn create-app --profile function --build maven hello-function
| Error Profile [function] is designed only for extension and not direct usage
できあがったプロジェクトには、テストコードなども含まれています。
$ find -type f
./mvnw.cmd
./.mvn/jvm.config
./.mvn/wrapper/maven-wrapper.properties
./.mvn/wrapper/MavenWrapperDownloader.java
./.mvn/wrapper/maven-wrapper.jar
./.gitignore
./mvnw
./pom.xml
./micronaut-cli.yml
./src/main/java/hello/function/HelloFunctionFunction.java
./src/main/java/hello/function/Application.java
./src/main/resources/application.yml
./src/main/resources/logback.xml
./src/test/java/hello/function/HelloFunctionFunctionTest.java
./src/test/java/hello/function/HelloFunctionClient.java
スケルトンのfunctionは、こんな感じです。
src/main/java/hello/function/HelloFunctionFunction.java
package hello.function;
import io.micronaut.function.FunctionBean;
import java.util.function.Supplier;
@FunctionBean("hello-function")
public class HelloFunctionFunction implements Supplier<String> {
@Override
public String get() {
return "hello-function";
}
}
functionを定義する方法は、FunctionBean
として作成する方法と、Factory
を使って作成する方法があるようです。
今回は、FunctionBean
を使った方法で実装されているというわけですね。
この場合、関数インターフェースを実装する必要があるようですが、利用できるインターフェースはSupplier
、Consumer
、BiConsumer
、Function
、BiFunction
のようです。
main
メソッドを持ったクラスは、こういう感じで。
src/main/java/hello/function/Application.java
package hello.function;
import io.micronaut.runtime.Micronaut;
public class Application {
public static void main(String[] args) {
Micronaut.run(Application.class);
}
}
実行するfunctionは、設定ファイルで指定されています。これは、FunctionBean
の名前ですね。
src/main/resources/application.yml
micronaut:
function:
name: hello-function
ドキュメントを見ると、複数のfunctionを含む場合は明示的に設定する必要があるみたいです。
CLIとして実行してみる
パッケージングして実行してみましょう。
結果が返ってきました。
$ java -jar target/hello-function-0.1.jar
12:56:07.817 [main] INFO i.m.context.env.DefaultEnvironment - Established active environments: [function]
hello-function
引数を受け取ったり、他のBeanをDIしたりしてみる
ちょっと構成を変えて、引数を受け取ったり他のBeanをDIしたりしてみましょう。
引数のメッセージを加工するだけの、Beanを作成します。
src/main/java/hello/function/MessageService.java
package hello.function;
import java.time.LocalDateTime;
import javax.inject.Singleton;
@Singleton
public class MessageService {
public String wrap(String message) {
return String.format("[%s] ★%s★", LocalDateTime.now(), message);
}
}
もとのfunctionは、このBeanをDIしつつ、実行時に引数を受け取るようにしてみましょう。関数インターフェースは、Function
を実装しました。
src/main/java/hello/function/HelloFunctionFunction.java
package hello.function;
import io.micronaut.function.FunctionBean;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.inject.Inject;
@FunctionBean("hello-function")
public class HelloFunctionFunction implements Function<HelloFunctionFunction.Request, HelloFunctionFunction.Response> {
@Inject
MessageService messageService;
@Override
public Response apply(Request request) {
String replyMessage = messageService.wrap(request.getMessage());
return new Response(replyMessage);
}
public static class Request {
String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
public static class Response {
String message;
public Response(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
}
コードが変わってしまったので、今回はテストをスキップしてパッケージング。
$ ./mvnw package -DskipTests=true
実行。
$ echo '{"message": "こんにちは、世界"}' | java -jar target/hello-function-0.1.jar
13:00:23.558 [main] INFO i.m.context.env.DefaultEnvironment - Established active environments: [function]
{"message":"[2019-03-05T13:00:24.185] ★こんにちは、世界★"}
引数を受け取りつつ、他のBeanをDIして実行できました。
functionをWebアプリケーションとしても実行できるようですが、今回はパスします。
実行環境へのデプロイは、そのうち…。