Funqy Google Cloud Functions
このガイドでは、Funqy 関数を Google Cloud Functions にデプロイする方法をクイックスタートコードで説明しています。
この技術は、previewと考えられています。 preview では、下位互換性やエコシステムでの存在は保証されていません。具体的な改善には設定や API の変更が必要になるかもしれませんが、 stable になるための計画は現在進行中です。フィードバックは メーリングリスト や GitHub の課題管理 で受け付けています。 とりうるステータスの完全なリストについては、 FAQの項目 を参照してください。 |
前提条件
このガイドを完成させるには、以下が必要です:
-
ざっと 30 minutes
-
IDE
-
JDK 11+ がインストールされ、
JAVA_HOME
が適切に設定されていること -
Apache Maven 3.8.6
-
使用したい場合は、 Quarkus CLI
-
Google Cloud のアカウント。無料アカウントで大丈夫です。
クイックスタート
Git レポジトリーをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.git
、 アーカイブ をダウンロードします。
このソリューションは funqy-google-cloud-functions-quickstart
ディレクトリー にあります。
Maven デプロイメントプロジェクトの作成
quarkus-funqy-google-cloud-functions
のエクステンションを持つアプリケーションを作成します。 以下の Maven コマンドを使って作成します。
コード
このコードには何も特別なものはありません。また、重要なこととして、Google Cloud に特化したものは何もありません。Funqy 関数はさまざまな環境にデプロイすることができ、Google Cloud Functions はそのうちの 1 つです。
関数の選択
Google Cloud Functions のデプロイごとにエクスポートできる Funqy 関数は 1 つだけです。プロジェクト内に @Funq
でアノテーションされたメソッドが 1 つしかない場合は、心配ありません。プロジェクト内に複数の関数が定義されている場合は、Quarkus application.properties
内で関数を選択する必要があります:
quarkus.funqy.export=greet
あるいは、gcloud
cliを使って Google Cloud Function を作成する際に、環境変数 QUARKUS_FUNQY_EXPORT
を設定することもできます。
ビルドとデプロイ
プロジェクトのビルド
quarkus build
./mvnw install
./gradlew build
これでコードがコンパイルされ、パッケージ化されます。
関数の作成
この例では、2 つのバックグラウンド関数とcloud events functionを作成します。バックグラウンド関数は、PubSub メッセージ、Cloud Storage イベント、Firestore イベントなどの Google Cloud eventに対応することができます。cloud events functionを使用すると、Cloud Events 仕様を使用して、サポートされているイベントに対応できます。
Quarkusは、Cloud Functionsの第1世代と第2世代をサポートしています。Cloud Functions gen 2の概要については、Google Cloud Functionsのドキュメントの このページ を参照してください。gen 2を使用するには、 --gen2 パラメータを追加する必要があります。
|
import javax.inject.Inject;
import io.cloudevents.CloudEvent;
import io.quarkus.funqy.Funq;
import io.quarkus.funqy.gcp.functions.event.PubsubMessage;
import io.quarkus.funqy.gcp.functions.event.StorageEvent;
public class GreetingFunctions {
@Inject GreetingService service; (1)
@Funq (2)
public void helloPubSubWorld(PubsubMessage pubSubEvent) {
String message = service.hello(pubSubEvent.data);
System.out.println(pubSubEvent.messageId + " - " + message);
}
@Funq (3)
public void helloGCSWorld(StorageEvent storageEvent) {
String message = service.hello("world");
System.out.println(storageEvent.name + " - " + message);
}
@Funq (4)
public void helloCloudEvent(CloudEvent cloudEvent) {
System.out.println("Receive event Id: " + cloudEvent.getId());
System.out.println("Receive event Subject: " + cloudEvent.getSubject());
System.out.println("Receive event Type: " + cloudEvent.getType());
System.out.println("Receive event Data: " + new String(cloudEvent.getData().toBytes()));
System.out.println("Be polite, say " + service.hello("world"));
}
}
関数の戻り値の型は、Mutiny 反応型も可能です。 |
-
インジェクションは Cloud Function 関数クラスの中で動作します。
-
これは、
io.quarkus.funqy.gcp.functions.event.PubsubMessage
をパラメーターとするバックグルアンド関数で、PubSub メッセージをデシリアライズする便利なクラスです。 -
これは、
io.quarkus.funqy.gcp.functions.event.StorageEvent
をパラメーターとするバックグラウンド関数で、Google Storage イベントをデシリアライズするための便利なクラスです。 -
これはクラウドイベントの関数で、パラメータとして
io.cloudevents.CloudEvent
を受け取り、その内部でgetData()
メソッドがイベントの内容(この場合はストレージイベント)を返します。
io.quarkus.funqy.gcp.functions.event パッケージ内で Google Cloud の共通イベントをデシリアライズするための便利なクラスを提供しています。これらのクラスは必須ではなく、任意のオブジェクトを使用することができます。
|
プロジェクトには複数の関数が含まれているので、どの関数をデプロイする必要があるかを application.properties
内の以下のプロパティーから指定する必要があります:
quarkus.funqy.export=helloPubSubWorld
アプリケーションのビルドと Google Cloud へのデプロイ
アプリケーションをビルドするには、 mvn clean package
からアプリケーションをパッケージ化することができます。target/deployment
リポジトリー内には、クラスとすべての依存関係が含まれた単一の JAR があります。
Then you will be able to use gcloud
to deploy your function to Google Cloud. The gcloud
command will be different depending on which event triggers your function.
We will use the Java 17 runtime but you can switch to the Java 11 runtime by using --runtime=java11 instead of --runtime=java17 on the deploy commands.
|
初めて
これは、Cloud Build がまだ有効化されていないことを意味します。このエラーを解決するには、エラーに表示されている URL を開き指示に従った後、数分待ってからコマンドを再試行してください。 |
バックグラウンド関数 - PubSub
このコマンドを使用して、Google Cloud Functions にデプロイします。
gcloud functions deploy quarkus-example-funky-pubsub \
--entry-point=io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction \
--runtime=java17 --trigger-resource hello_topic --trigger-event google.pubsub.topic.publish \
--source=target/deployment
Quarkus をブートストラップするのはこのクラスなので、エントリーポイントは常に |
--trigger-resource
オプションは PubSub トピックの名前を定義し、--trigger-event google.pubsub.topic.publish
オプションは、この関数がトピック内のすべてのメッセージ公開によってトリガーされることを定義します。
この関数にイベントをトリガーするには、 gcloud functions call
コマンドを使用します。
gcloud functions call quarkus-example-funky-pubsub —data ‘{“data”:”Pub/Sub”}’
--data '{"data":"Hello, Pub/Sub"}'
オプションでは、メッセージが PubSub に送信されるようにできます。
バックグラウンド関数 - クラウドストレージ
関数をデプロイする前に、バケットを作成する必要があります。
gsutil mb gs://quarkus-hello
そして、このコマンドを使って Google Cloud Functions にデプロイします。
gcloud functions deploy quarkus-example-funky-storage \
--entry-point=io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction \
--runtime=java17 --trigger-resource quarkus-hello --trigger-event google.storage.object.finalize \
--source=target/deployment
Quarkus をブートストラップするのはこのクラスなので、エントリーポイントは常に |
--trigger-resource
オプションは Cloud Storage のバケット名を定義します。また、--trigger-event google.storage.object.finalize
オプションはこのバケット内のすべての新規ファイルに対してこの関数がトリガーされることを定義します。
この関数にイベントをトリガーするには、 gcloud functions call
コマンドを使用します。
gcloud functions call quarkus-example-funky-storage --data '{"name":"test.txt"}'
--data '{"name":"test.txt"}'
オプションでは、偽のファイル名を指定することができ、この名前に対して偽のクラウドストレージイベントが作成されます。
また、Web コンソールのコマンドラインを使用して、Cloud Storage にファイルを追加するだけでも簡単にできます。
Cloud Events Functions - クラウドストレージ
Cloud Events Function は、Cloud Functions gen 2のみの機能です。 |
関数をデプロイする前に、バケットを作成する必要があります。
gsutil mb gs://quarkus-hello
そして、このコマンドを使って Google Cloud Functions にデプロイします。
gcloud functions deploy quarkus-example-cloud-event --gen2 \
--entry-point=io.quarkus.funqy.gcp.functions.FunqyCloudEventsFunction \
--runtime=java17 --trigger-bucket=example-cloud-event --source=target/deployment
Quarkus をブートストラップするのはこのクラスなので、エントリーポイントは常に |
--trigger-bucket=
オプションは、Cloud Storage バケットの名称を定義します。
イベントをトリガーするために、GCS example-cloud-event
のバケットにファイルを送信することができます。
Running locally
The easiest way to locally run your function is using the Cloud Function invoker JAR.
以下のコマンドで Maven 経由でダウンロードできます。
mvn dependency:copy \
-Dartifact='com.google.cloud.functions.invoker:java-function-invoker:1.1.1' \
-DoutputDirectory=.
invokerを使用する前に、まず、以下のように関数をビルドする必要があります。
quarkus build
./mvnw install
./gradlew build
その後、これは、ローカルで関数を起動するために使用することができます。このコマンドは、関数の種類とイベントの種類に依存します。
バックグラウンド関数 - PubSub
バックグラウンド関数の場合は、 io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
のターゲットクラスで invoker を起動します。
java -jar java-function-invoker-1.1.1.jar \
--classpath target/funqy-google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
--target io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
--classpath パラメーターには、関数クラスと Quarkus 関連のすべてのクラスを含む、先の手順でパッケージ化された JAR を指定する必要があります。
|
起動後、HTTP 呼び出しにイベントを含むペイロードを付与することでバックグラウンド関数を呼び出すことができます。
curl localhost:8080 -d '{"data":{"data":"world"}}'
これは、PubSub のバックグラウンド関数を PubSubMessage で呼び出します {"data":"hello”}
。
バックグラウンド関数 - クラウドストレージ
バックグラウンド関数の場合は、 io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
のターゲットクラスで invoker を起動します。
java -jar java-function-invoker-1.1.1.jar \
--classpath target/funqy-google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
--target io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
--classpath パラメーターには、関数クラスと Quarkus 関連のすべてのクラスを含む、先の手順でパッケージ化された JAR を指定する必要があります。
|
起動後、HTTP 呼び出しにイベントを含むペイロードを付与することでバックグラウンド関数を呼び出すことができます。
curl localhost:8080 -d '{"data":{"name":"text"}}'
これは、Cloud Storage のイベント {"name":"file.txt"}
(file.txt
ファイル上のイベント) で PubSub のバックグラウンド関数を呼び出します。
Cloud Events Functions - クラウドストレージ
Cloud Events Function は、Cloud Functions gen 2のみの機能です。 |
cloud events functionsの場合は、 io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
をターゲットクラスとして invoker を起動します。
java -jar java-function-invoker-1.1.1.jar \
--classpath target/funqy-google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
--target io.quarkus.funqy.gcp.functions.FunqyCloudEventsFunction
--classpath パラメーターには、関数クラスと Quarkus 関連のすべてのクラスを含む、先の手順でパッケージ化された JAR を指定する必要があります。
|
起動後、HTTP 呼び出しにイベントを含むペイロードを付与することでバックグラウンド関数を呼び出すことができます。
curl localhost:8080 \
-X POST \
-H "Content-Type: application/json" \
-H "ce-id: 123451234512345" \
-H "ce-specversion: 1.0" \
-H "ce-time: 2020-01-02T12:34:56.789Z" \
-H "ce-type: google.cloud.storage.object.v1.finalized" \
-H "ce-source: //storage.googleapis.com/projects/_/buckets/MY-BUCKET-NAME" \
-H "ce-subject: objects/MY_FILE.txt" \
-d '{
"bucket": "MY_BUCKET",
"contentType": "text/plain",
"kind": "storage#object",
"md5Hash": "...",
"metageneration": "1",
"name": "MY_FILE.txt",
"size": "352",
"storageClass": "MULTI_REGIONAL",
"timeCreated": "2020-04-23T07:38:57.230Z",
"timeStorageClassUpdated": "2020-04-23T07:38:57.230Z",
"updated": "2020-04-23T07:38:57.230Z"
}'
これにより、 MY_FILE.txt
ファイルのイベントでcloud events functionが呼び出されます。
Testing your function
Quarkus provides built-in support for testing your Funqy Google Cloud functions via the quarkus-test-google-cloud-functions
dependency.
To use it, you must add the following test dependency in your pom.xml
.
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-google-cloud-functions</artifactId>
<scope>test</scope>
</dependency>
This extension provides a @WithFunction
annotation that can be used to annotate @QuarkusTest
test cases to start a Cloud Function invoker before you test cases and stop it at the end. This annotation must be configured with the type of the function you want to launch, and optionally the name of the function in case you have multiple functions inside your application.
バックグラウンド関数 - PubSub
import static io.restassured.RestAssured.given;
import org.junit.jupiter.api.Test;
import io.quarkus.google.cloud.functions.test.FunctionType;
import io.quarkus.google.cloud.functions.test.WithFunction;
import io.quarkus.test.junit.QuarkusTest;
@QuarkusTest (1)
@WithFunction(FunctionType.FUNQY_BACKGROUND) (2)
class GreetingFunctionsPubsubTest {
@Test
public void test() {
given()
.body("{\"data\":{\"data\":\"world\"}}") (3)
.when()
.post()
.then()
.statusCode(200);
}
}
-
This is a standard Quarkus test that must be annotated by
@QuarkusTest
. -
@WithFunction(FunctionType.FUNQY_BACKGROUND)
indicates to launch the function as a Funqy background function. If multiple functions exist in the same application, thefunctionName
attribute must be used to denote which one should be launched. -
REST-assured is used to test the function,
{"data":"world"}
will be sent to it via the invoker.
バックグラウンド関数 - クラウドストレージ
import static io.restassured.RestAssured.given;
import org.junit.jupiter.api.Test;
import io.quarkus.google.cloud.functions.test.FunctionType;
import io.quarkus.google.cloud.functions.test.WithFunction;
import io.quarkus.test.junit.QuarkusTest;
@QuarkusTest (1)
@WithFunction(FunctionType.FUNQY_BACKGROUND) (2)
class GreetingFunctionsStorageTest {
@Test
public void test() {
given()
.body("{\"data\":{\"name\":\"hello.txt\"}}") (2)
.when()
.post()
.then()
.statusCode(200);
}
}
-
This is a standard Quarkus test that must be annotated by
@QuarkusTest
. -
@WithFunction(FunctionType.FUNQY_BACKGROUND)
indicates to launch the function as a Funqy background function. If multiple functions exist in the same application, thefunctionName
attribute must be used to denote which one should be launched. -
REST-assured is used to test the function,
{"name":"hello.txt"}
will be sent to it via the invoker.
Cloud Events Functions - クラウドストレージ
Cloud Events Function は、Cloud Functions gen 2のみの機能です。 |
import static io.restassured.RestAssured.given;
import org.junit.jupiter.api.Test;
import io.quarkus.google.cloud.functions.test.FunctionType;
import io.quarkus.google.cloud.functions.test.WithFunction;
import io.quarkus.test.junit.QuarkusTest;
@QuarkusTest (1)
@WithFunction(FunctionType.FUNQY_CLOUD_EVENTS) (2)
class GreetingFunctionsCloudEventTest {
@Test
public void test() {
given()
.body("{\n" + (3)
" \"bucket\": \"MY_BUCKET\",\n" +
" \"contentType\": \"text/plain\",\n" +
" \"kind\": \"storage#object\",\n" +
" \"md5Hash\": \"...\",\n" +
" \"metageneration\": \"1\",\n" +
" \"name\": \"MY_FILE.txt\",\n" +
" \"size\": \"352\",\n" +
" \"storageClass\": \"MULTI_REGIONAL\",\n" +
" \"timeCreated\": \"2020-04-23T07:38:57.230Z\",\n" +
" \"timeStorageClassUpdated\": \"2020-04-23T07:38:57.230Z\",\n" +
" \"updated\": \"2020-04-23T07:38:57.230Z\"\n" +
" }")
.header("ce-id", "123451234512345") (4)
.header("ce-specversion", "1.0")
.header("ce-time", "2020-01-02T12:34:56.789Z")
.header("ce-type", "google.cloud.storage.object.v1.finalized")
.header("ce-source", "//storage.googleapis.com/projects/_/buckets/MY-BUCKET-NAME")
.header("ce-subject", "objects/MY_FILE.txt")
.when()
.post()
.then()
.statusCode(200);
}
}
-
This is a standard Quarkus test that must be annotated by
@QuarkusTest
. -
@WithFunction(FunctionType.FUNQY_CLOUD_EVENTS)
indicates to launch the function as a Funqy cloud events function. If multiple functions exist in the same application, thefunctionName
attribute must be used to denote which one should be launched. -
REST-assured is used to test the function, this payload that describe a storage event will be sent to it via the invoker.
-
The cloud events headers must be sent via HTTP headers.
次のステップ
Google Cloud FunctionsのJAX-RS、Servlet、Vert.xのサポートを探しているなら、 Google Cloud Functions HTTP binding が存在します。