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 supports the SmallRye Mutiny Uni
reactive type as a return type. The only requirement is that
the Uni
must fill out the generic type.
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 has become a very common way to write services over the past decade. While Funqy
has an HTTP binding it is not a replacement for REST. Because Funqy has to work across a variety
of protocols and function cloud platforms, it is very minimalistic and constrained. For example, if you
use Funqy you lose the ability to link (think URIs) to the data your functions spit out. You also
lose the ability to leverage cool HTTP features like cache-control
and conditional GETs. Many
developers will be ok with that as many won’t be using these REST/HTTP features or styles. You’ll
have to make the decision on what camp you are in. Quarkus does support REST integration (through Jakarta REST,
Spring MVC, Vert.x Web, and Servlet) with
various cloud/function providers, but there are some disadvantages of using that approach as well. For example,
if you want to do HTTP with AWS Lambda, this requires you to use the AWS API Gateway which may
slow down deployment and cold start time or even cost you more.
The purpose of Funqy is to allow you to write cross-provider functions so that you can move off of your current function provider if, for instance, they start charging you a lot more for their service. Another reason you might not want to use Funqy is if you need access specific APIs of the target function environment. For example, developers often want access to the AWS Context on Lambda. In this case, we tell them they may be better off using the Quarkus AWS Lambda integration instead.