Funqy
Quarkus Funqy は、Quarkus のサーバーレス戦略の一部であり、AWS Lambda、Azure Functions、Google Cloud Functions、Knative、Knative Events(Cloud Events)などの様々な FaaS 環境にデプロイ可能なファンクションを書くためのポータブルな Java API を提供することを目的としています。また、スタンドアロンのサービスとしても使用することができます。
Funqy は複数の異なるクラウド、ファンクションプロバイダーやプロトコルに跨った抽象化を提供するため、その API は非常にシンプルである必要があり、ユーザーが使い慣れている他のリモーティング抽象化で提供される機能を全て備えているとは限りません。一方で、Funqy は可能な限り最適化され、かつ小さいという良い副次的効果があります。これは、Funqy は柔軟性を少し犠牲にしている分、オーバーヘッドが非常に少ないフレームワークであることを意味しています。
Funqy の基礎
Funqy API はシンプルです。メソッドに @Funq
をアノテーションします。このメソッドはオプションの入力パラメータを1つだけ持つことができ、レスポンスを返しても返さなくても問題ありません。
import io.quarkus.funqy.Funq;
public class GreetingFunction {
@Funq
public String greet(String name) {
return "Hello " + name;
}
}
デフォルトのコンストラクタを持ち、Java Bean の規約に従った Java クラスは、入力と出力に使用できます。パラメータや戻り値の型として宣言された Java のクラスは、Funqy のランタイムが期待する型となります。Funqy は起動時間を短縮するためにビルド時にクラスのイントロスペクションを行うため、派生クラスは実行時に Funqy のマーシャリングレイヤーに意識されることはありません。
以下に、POJO を入出力の型として使用した例をご紹介します。
public class GreetingFunction {
public static class Friend {
String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
public static class Greeting {
String msg;
public Greeting() {}
public Greeting(String msg) { this.msg = msg }
public String getMessage() { return msg; }
public void setMessage(String msg) { this.msg = msg; }
}
@Funq
public Greeting greet(Friend friend) {
return new Greeting("Hello " + friend.getName());
}
}
非同期リアクティブ型
Funqy は戻り値の型として Smallrye Mutiny Uni
リアクティブ型をサポートしています。 Uni
がジェネリクス型として記述される必要があります。
import io.quarkus.funqy.Funq;
import io.smallrye.mutiny.Uni;
public class GreetingFunction {
@Funq
public Uni<Greeting> reactiveGreeting(String name) {
...
}
}
ファンクション名
ファンクション名のデフォルト値はメソッド名で、大文字と小文字は区別されます。ファンクションを別の名前で参照したい場合は、以下のように @Funq
アノテーションにパラメータを記述します。
import io.quarkus.funqy.Funq;
public class GreetingFunction {
@Funq("HelloWorld")
public String greet(String name) {
return "Hello " + name;
}
}
Funqy DI
それぞれの Funqy Java クラスは Quarkus Arc コンポーネントであり、CDI または Spring DI による依存性注入をサポートしています。Spring DI では、ビルドに quarkus-spring-di
の依存関係を含める必要があります。
Funqy クラスのデフォルトのオブジェクトライフサイクルは @Dependent
となります。
import io.quarkus.funqy.Funq;
import javax.inject.Inject;
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class GreetingFunction {
@Inject
GreetingService service;
@Funq
public Greeting greet(Friend friend) {
Greeting greeting = new Greeting();
greeting.setMessage(service.greet(friend.getName()));
return greeting;
}
}
コンテキストの注入
通常、 Funqy API はプロトコル (例: HTTP ) やファンクション API (例: AWS Lambda) に固有の抽象化を注入したり、使用したりすることはできません。例外もあり、デプロイ先の環境に応じたコンテキスト情報を注入できる場合もあります。
ランタイムに固有のコンテキスト情報を注入することは推奨されません。 ファンクションを移植性の高いものにしてください。 |
コンテキスト情報は、ファンクションのパラメータやクラスのフィールドに使用できる @Context
アノテーションを介して注入されます。例として、 Funqy Knative Cloud Events に搭載されている io.quarkus.funqy.knative.events.CloudEvent
インターフェースがあります。
import io.quarkus.funqy.Funq;
import io.quarkus.funqy.Context;
import io.quarkus.funqy.knative.events.CloudEvent;
public class GreetingFunction {
@Funq
public Greeting greet(Friend friend, @Context CloudEvent eventInfo) {
System.out.println("Received greeting request from: " eventInfo.getSource());
Greeting greeting = new Greeting();
greeting.setMessage("Hello " + friend.getName()));
return greeting;
}
}
Funqy を使うべきか?
REST over HTTP は、過去10年間でサービスを実装するための非常に一般的な方法になりました。
Funqy は HTTP バインディングを持っていますが、REST の代わりになるものではありません。
Funqy は様々なプロトコルや機能を持つクラウドプラットフォームで動作するために、非常に小さく、制約の多いものになっています。
例えば、Funqy を使うと、ファンクションが出力するデータへのリンク(URIのようなもの)の機能が失われます。
また、 cache-control
や条件付き GET のような素晴らしい HTTP の機能を利用することもできなくなります。
多くの開発者は、これらの REST/HTTP の機能やスタイルを使用しないため、問題にはならないと考えられます。
どの方針に従うかは、利用者が自分で判断する必要があります。
Quarkus は、 JAX-RS、Spring MVC、Vert.x Web、Servletによるさまざまなクラウドやファンクションプロバイダーとの REST 統合をサポートしていますが、
そのアプローチを使用することにもいくつかのデメリットがあります。
例えば、 AWS LambdaにおけるHTTPの利用 を行いたい場合、AWS API Gatewayを使用する必要があり、デプロイやコールドスタート時間が遅くなる、あるいはコストがかかる可能性があります。
Funqy の目的は、プロバイダーを跨いだファンクションを書けるようにすることであり、例えば、現在のファンクションプロバイダーの利用料金が上昇してしまった場合に、そこから移動できるようにすることです。対象のファンクション実行環境の特定の API にアクセスする必要がある場合は、Funqy を使わない理由となり得ます。よくある例としては、開発者が Lambda で AWS Context にアクセスしたい場合です。この場合は、代わりに Quarkus Amazon Lambda による統合を使用した方が良い場合があります。