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 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) に固有の抽象化を注入したり、使用したりすることはできません。例外もあり、デプロイ先の環境に応じたコンテキスト情報を注入できる場合もあります。
| ランタイムに固有のコンテキスト情報を注入することはお勧めしません。 Function を移植性の高いものにしてください。 |
コンテキスト情報は、ファンクションのパラメータやクラスのフィールドに使用できる @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では、さまざまなクラウド/関数プロバイダーとのREST連携(JAX-RS、Spring MVC、Vert.x Web、Servletによる)をサポートしていますが、そのアプローチを使うことによるデメリットもあります。
例えば、 HTTPでAWS Lambda を行いたい場合、AWS API Gatewayを利用する必要があり、
デプロイやコールドスタート時間が遅くなったり、コストがかかったりすることがあります。
Funqy の目的は、プロバイダーを跨いだファンクションを書けるようにすることであり、例えば、現在のファンクションプロバイダーの利用料金が上昇してしまった場合に、そこから移動できるようにすることです。対象のファンクション実行環境の特定の API にアクセスする必要がある場合は、Funqy を使わない理由となり得ます。よくある例としては、開発者が Lambda で AWS Context にアクセスしたい場合です。この場合は、代わりに Quarkus Amazon Lambda による統合を使用した方が良い場合があります。