Micronaut Severless Function Micronaut has the ability to create Serverless Functions.
The advantage over other frameworks such as Spring seems to be that Micronaut has a mechanism to resolve dependencies at compile time and a light memory footprint.
It seems that the created Function can be deployed to AWS Lambda, OpenFaaS, etc.
I would like to easily try this function to create a Serverless Function of Micronaut.
The environment is here.
$ mn -V
| Micronaut Version: 1.0.4
| JVM Version: 1.8.0_191
Create a project with --profile as function-aws.
$ mn create-app --profile function-aws --build maven hello-function
$ cd hello-function
The Profile of function that can be specified seems to be only 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
If you just write function, you will get angry that there is no such profile.
$ mn create-app --profile function --build maven hello-function
| Error Profile [function] is designed only for extension and not direct usage
The resulting project also includes test code and more.
$ 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
The skeleton function looks like this.
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";
    }
}
There seems to be a way to define a function, one is to create it as FunctionBean and the other is to create it using Factory.
This time, it is implemented by the method using Function Bean.
In this case, it seems that you need to implement a function interface, but the available interfaces are like Supplier, Consumer, BiConsumer, Function, BiFunction.
A class with a main method looks like this.
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);
    }
}
The function to execute is specified in the configuration file. This is the name of the Function Bean.
src/main/resources/application.yml
micronaut:
    function:
        name: hello-function
Looking at the documentation, it seems that if you have multiple functions, you need to set them explicitly.
Let's package and run it.
The result is returned.
$ 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
Let's change the configuration a little and take arguments and DI other beans.
Create a bean that just processes the argument message.
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);
    }
}
Let's make the original function DI this bean and receive arguments at runtime. The function interface implements 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;
        }
    }
}
The code has changed, so this time I skipped the test and packaged it.
$ ./mvnw package -DskipTests=true
Run.
$ echo '{"message": "Hello World"}' | 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]★ Hello, world ★"}
I was able to DI and execute other beans while receiving arguments.
It seems that function can also be executed as a web application, but this time it passes.
Deployment to the execution environment will be soon ...
Recommended Posts