MicronautでPostgreSQLのリアクティブアクセスをネイティブ化できた

きしださんの記事を見て

nowokay.hatenablog.com

このときはMicronautを使ってもネイティブ化できなかったみたいだけど、今のバージョンならできるんじゃないかなと思ってやってみたら、できたよ。ちょっとごにょっとしたけど。

バージョンはこんな感じ。GraalVMは1.0.0のRC15:

❯ mn --version
| Micronaut Version: 1.1.0
| JVM Version: 1.8.0_202

❯ sdk current java

Using java version 1.0.0-rc-15-grl

コードはここに置いといた。あ、しまった。ネイティブイメージもpushしてしまった。まいっか。

github.com

じゃ、やったことを順番に書いておく。

## アプリを生成

postgres-reactivegraal-native-image をつけてCLIアプリを生成。

❯ mn create-cli-app micronaut-postgres-reactive \
        --features postgres-reactive,graal-native-image

graal-native-image をつけとくと、ネイティブ化用のライブラリーと設定ファイルがついてくる。

具体的には build.gradle にこの2つが入ってくるのと

    annotationProcessor "io.micronaut:micronaut-graal"
    ...
    compileOnly "com.oracle.substratevm:svm"

META-INFの中に

src/main/resources/META-INF/native-image/micronaut.postgres.reactive/micronaut-postgres-reactive-application/native-image.properties

ってファイルが作られてて(長い・・・プロジェクト名を短くすれば良かったな)

内容はこうなってる

Args = -H:IncludeResources=logback.xml|application.yml \
       -H:Name=micronaut-postgres-reactive \
       -H:Class=micronaut.postgres.reactive.Application

## PostgreSQLコンテナ

こんな感じのDocker ComposeでPostgreSQLを用意した。 docker ってディレクトリに入れといた。

docker-compose.yml

db:
  image: postgres:11.2-alpine
  ports:
    - "5432:5432"
  environment:
    - POSTGRES_PASSWORD=mypass
    - POSTGRES_DB=mydb
  volumes:
    - "./initdb.d:/docker-entrypoint-initdb.d"

initdb.d の中にはコンテナを初回起動したときに実行されるSQLを入れて:

CREATE TABLE IF NOT EXISTS users (
  id SERIAL,
  first_name VARCHAR(30),
  last_name VARCHAR(30),
  CONSTRAINT pk_user PRIMARY KEY (id)
);

INSERT INTO users VALUES (1, 'James', 'Carter') ON CONFLICT DO NOTHING;
INSERT INTO users VALUES (2, 'Helen', 'Leary') ON CONFLICT DO NOTHING;
INSERT INTO users VALUES (3, 'Linda', 'Douglas') ON CONFLICT DO NOTHING;
INSERT INTO users VALUES (4, 'Rafael', 'Ortega') ON CONFLICT DO NOTHING;
INSERT INTO users VALUES (5, 'Henry', 'Stevens') ON CONFLICT DO NOTHING;
INSERT INTO users VALUES (6, 'Sharon', 'Jenkins') ON CONFLICT DO NOTHING;

あとコンテナのPrefixを指定したかったので .env も置いといた。

COMPOSE_PROJECT_NAME=micronaut-postgres-reactive

ほんで、起動しとく

❯  docker-compose up

## CLIアプリの実装

これはきしださんのそのまま。DBの情報は少し違うけど。

application.yml

postgres:
  reactive:
    client:
      port: 5432
      host: localhost
      database: mydb
      user: postgres
      password: mypass
      # maxSize: 5

インデントが変なのは、Issueあげといた

https://github.com/micronaut-projects/micronaut-profiles/issues/148

MicronautPostgresReactiveCommand.java

    @Inject
    PgPool client;
    public void data() {
        client.rxQuery("select * from users")
            .map(rowSet -> {
                List<String> result = new ArrayList<>();
                PgIterator ite = rowSet.iterator();
                while(ite.hasNext()) {
                    Row row = ite.next();
                    result.add(row.getString("first_name"));
                }
                return result;
            })
            .blockingGet()
            .stream()
            .forEach(System.out::println);
    }

で実行すると

❯ ./gradlew assemble
...

❯ java -jar build/libs/micronaut-postgres-reactive-0.1.jar
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
James
Helen
Linda
Rafael
Henry
Sharon

OKだね。じゃ、ネイティブ化してみよう

❯ native-image --no-server -cp build/libs/micronaut-postgres-reactive-0.1.jar

## ビルド失敗

Netty周りのエラーが出た。 Unsafe とかのやつ。あれー?なんでだろう?この前見たとき対応入ってたのになー:

bufferings.hatenablog.com

と思ってよく見てみたら、Nettyのネイティブ化用設定が入ったライブラリーがないやないか。入れてみるか。

    compile "io.micronaut:micronaut-http-server-netty"

そしたらビルド通ったや。うーん。

## んで実行!

しても何も出力されない…あれー。なんでだろう?って見てたら。これか…さっきの native-image.properties

Args = -H:IncludeResources=logback.xml|application.yml \
       -H:Name=micronaut-postgres-reactive \
       -H:Class=micronaut.postgres.reactive.Application

エントリーポイントが Application になってるからこれをこう書き換えて:

Args = -H:IncludeResources=logback.xml|application.yml \
       -H:Name=micronaut-postgres-reactive \
       -H:Class=micronaut.postgres.reactive.MicronautPostgresReactiveCommand

ビルドし直したら動いたー

❯ ./micronaut-postgres-reactive
James
Helen
Linda
Rafael
Henry
Sharon

うーん。なんかちょっとイマイチな感じもあるけど。まぁ、動いたからいっかな。