MicronautでReactiveなサーバーを書く

# Micronaut Reactive HTTP Request Processing

Micronautは、Netty上に構築されているため、Non-BlockingなI/Oを行うことも可能だとか。

[Reactive HTTP Request Processing](https://docs.micronaut.io/1.0.4/guide/index.html#reactiveServer)

> If your controller method returns a non-blocking type such as an RxJava Observable or a CompletableFuture then Micronaut will use the Event loop thread to subscribe to the result.

`Controller`のメソッドが、RxJavaの`Observable`や`CompletableFuture`を返すとEventループスレッドを使って、`Controller`の結果をサブスクライブします、と。

> If however you return any other type then Micronaut will execute your @Controller method in a preconfigured I/O thread pool.

それ以外の型を返す場合は、I/Oスレッドプールを使用するそうです。

`Controller`の戻り値の型が大事なんですねぇ。

まあ、簡単にですが、使ってみましょう。


# 環境

今回の環境は、こちら。

```shell
$ mn -V
| Micronaut Version: 1.0.4
| JVM Version: 1.8.0_191
```


# サンプルアプリケーション

とりあえず、ひな型のプロジェクトを作成します。

```shell
$ mn create-app hello-reactive --build maven
$ cd hello-reactive
```

`main`メソッドを持ったクラスは、とりあえずそのままにして

src/main/java/hello/reactive/Application.java

```java
package hello.reactive;

import io.micronaut.runtime.Micronaut;

public class Application {

    public static void main(String[] args) {
        Micronaut.run(Application.class);
    }
}
```

`Controller`を作ってみます。

src/main/java/hello/reactive/HelloReactiveController.java

```java
package hello.reactive;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Body;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Post;
import io.reactivex.Flowable;
import org.reactivestreams.Publisher;

@Controller("/reactive")
public class HelloReactiveController {

}
```

メソッドの中身を書いていきましょう。

まずは、どんな型を返せばよいのか、ドキュメントで確認してみます。

[Reactive Responses](https://docs.micronaut.io/1.0.4/guide/index.html#reactiveResponses)

* `org.reactivestreams.Publisher`
  * RxJavaの`Single`や`Observable`
  * Reactorの`Mono`や`Flux`
* `java.util.concurrent.CompletableFuture`

という感じみたいです。

なお、メソッドの引数についても`CompletableFuture`やReactiveな型を使ってよいみたいです。

1秒おきに、メッセージを返す`text/event-stream`なメソッドを作ってみます。

```java
    @Get(value = "/hello", produces = MediaType.TEXT_EVENT_STREAM)
    public Publisher<String> hello() {
        return Flowable
                .fromArray("Hello Reactive")
                .repeat(10)
                .delay(1, TimeUnit.SECONDS)
                .map(m -> String.format("[%s] %s", LocalDateTime.now(), m));
    }
```

作成されたプロジェクトの依存関係を調べると、RxJavaがあったのでこちらを利用。

```shell
$ ./mvnw dependency:tree

[INFO] +- io.micronaut:micronaut-runtime:jar:1.0.4:compile
[INFO] |  +- io.micronaut:micronaut-aop:jar:1.0.4:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.8:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.8:compile
[INFO] |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.9.8:compile
[INFO] |  +- io.reactivex.rxjava2:rxjava:jar:2.2.2:compile
```

起動させて、確認。

```shell
$ curl -i localhost:8080/reactive/hello
HTTP/1.1 200 OK
transfer-encoding: chunked
Date: Wed, 20 Feb 2019 13:00:07 GMT
transfer-encoding: chunked
content-type: text/event-stream

data: [2019-02-20T13:00:08.861] Hello Reactive

data: [2019-02-20T13:00:09.940] Hello Reactive

data: [2019-02-20T13:00:10.943] Hello Reactive

data: [2019-02-20T13:00:11.946] Hello Reactive

data: [2019-02-20T13:00:12.948] Hello Reactive

data: [2019-02-20T13:00:13.950] Hello Reactive

data: [2019-02-20T13:00:14.953] Hello Reactive

data: [2019-02-20T13:00:15.954] Hello Reactive

data: [2019-02-20T13:00:16.956] Hello Reactive

data: [2019-02-20T13:00:17.959] Hello Reactive

```

なんか、それっぽく動いています。

引数を受け取るものも書いてみましょう。

```java
    @Post(value = "echo", consumes = MediaType.TEXT_PLAIN, produces = MediaType.TEXT_EVENT_STREAM)
    public Publisher<String> echo(@Body Flowable<String> text) {
        return text.map(t -> "★" + t + "★");
    }
```

入力もストリームになっているわけではありませんが…。

```java
$ curl -i -XPOST -H 'Content-Type: text/plain' localhost:8080/reactive/echo -d 'hello'
HTTP/1.1 200 OK
transfer-encoding: chunked
Date: Wed, 20 Feb 2019 13:01:29 GMT
transfer-encoding: chunked
content-type: text/event-stream

data: ★hello★

```

これ、依存関係にReactorとか入れてもいいんでしょうかね？

とりあえず、簡単な確認はできましたと。