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クラスは入力と出力としても使用でき、Java Bean の規約に従う必要があり、デフォルトのコンストラクタを持たなければなりません。パラメータや戻り値の型として宣言された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 jakarta.inject.Inject;
import jakarta.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は、(Jakarta REST、Spring MVC、Vert.x Web、Servletを通じて)様々なクラウド/ファンクションプロバイダーとのREST統合をサポートしていますが、そのアプローチを使うことにはデメリットもあります。例えば、 AWS LambdaでHTTP を行いたい場合、AWS API Gatewayを使用する必要があり、デプロイやコールドスタート時間が遅くなったり、コストがかかったりする可能性があります。
Funqyの目的は、クロスプロバイダー関数を書けるようにすることで、例えば、現在の関数プロバイダーが高額な料金を請求するようになった場合、そのプロバイダーから移ることができるようにすることです。 Funqyを使いたくないもう一つの理由として、ターゲット関数環境の特定のAPIにアクセスする必要がある場合もあるでしょう。例えば、開発者はLambdaのAWS Contextにアクセスしたいことがよくあります。この場合、代わりに QuarkusのAWS Lambda インテグレーションを使用する方がよいかもしれません。