The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
Back to Guides

Funqy Google Cloud Functions

このガイドでは、Funqy 関数を Google Cloud Functions にデプロイする方法をクイックスタートコードで説明しています。

この技術は、previewと考えられています。

preview では、下位互換性やエコシステムでの存在は保証されていません。具体的な改善には設定や API の変更が必要になるかもしれませんが、 stable になるための計画は現在進行中です。フィードバックは メーリングリストGitHub の課題管理 で受け付けています。

とりうるステータスの完全なリストについては、 FAQの項目 を参照してください。

前提条件

このガイドを完成させるには、以下が必要です:

Google Cloud にログイン

アプリケーションのデプロイには Google Cloud へのログインが必要で、以下のように行うことが出来ます:

gcloud auth login

クイックスタート

Git レポジトリーをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.gitアーカイブ をダウンロードします。

このソリューションは funqy-google-cloud-functions-quickstart ディレクトリー にあります。

Maven デプロイメントプロジェクトの作成

quarkus-funqy-google-cloud-functions のエクステンションを持つアプリケーションを作成します。 以下の Maven コマンドを使って作成します。

コマンドラインインタフェース
quarkus create app org.acme:funqy-google-cloud-functions \
    --extension='funqy-google-cloud-functions' \
    --no-code
cd funqy-google-cloud-functions

Gradleプロジェクトを作成するには、 --gradle または --gradle-kotlin-dsl オプションを追加します。

Quarkus CLIのインストール方法や使用方法については、<a href="cli-tooling.html">Quarkus CLIガイド</a> を参照してください。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:2.16.4.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=funqy-google-cloud-functions \
    -Dextensions='funqy-google-cloud-functions' \
    -DnoCode
cd funqy-google-cloud-functions

Gradleプロジェクトを作成するには、 -DbuildTool=gradle または -DbuildTool=gradle-kotlin-dsl オプションを追加します。

コード

このコードには何も特別なものはありません。また、重要なこととして、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
Maven
./mvnw install
Gradle
./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 反応型も可能です。
  1. インジェクションは Cloud Function 関数クラスの中で動作します。

  2. これは、io.quarkus.funqy.gcp.functions.event.PubsubMessage をパラメーターとするバックグルアンド関数で、PubSub メッセージをデシリアライズする便利なクラスです。

  3. これは、io.quarkus.funqy.gcp.functions.event.StorageEvent をパラメーターとするバックグラウンド関数で、Google Storage イベントをデシリアライズするための便利なクラスです。

  4. これはクラウドイベントの関数で、パラメータとして 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.

初めて gcloud beta functions deploy を実行すると、以下のようなエラーメッセージが表示されます:

ERROR: (gcloud.functions.deploy) OperationError: code=7, message=Build Failed: Cloud Build has not been used in project <project_name> before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudbuild.googleapis.com/overview?project=<my-project> then retry.

これは、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 をブートストラップするのはこのクラスなので、エントリーポイントは常に io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction である必要があります。

--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 をブートストラップするのはこのクラスなので、エントリーポイントは常に io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction である必要があります。

--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 をブートストラップするのはこのクラスなので、エントリーポイントは常に io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction である必要があります。

--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
Maven
./mvnw install
Gradle
./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);
    }
}
  1. This is a standard Quarkus test that must be annotated by @QuarkusTest.

  2. @WithFunction(FunctionType.FUNQY_BACKGROUND) indicates to launch the function as a Funqy background function. If multiple functions exist in the same application, the functionName attribute must be used to denote which one should be launched.

  3. 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);
    }
}
  1. This is a standard Quarkus test that must be annotated by @QuarkusTest.

  2. @WithFunction(FunctionType.FUNQY_BACKGROUND) indicates to launch the function as a Funqy background function. If multiple functions exist in the same application, the functionName attribute must be used to denote which one should be launched.

  3. 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);
    }
}
  1. This is a standard Quarkus test that must be annotated by @QuarkusTest.

  2. @WithFunction(FunctionType.FUNQY_CLOUD_EVENTS) indicates to launch the function as a Funqy cloud events function. If multiple functions exist in the same application, the functionName attribute must be used to denote which one should be launched.

  3. REST-assured is used to test the function, this payload that describe a storage event will be sent to it via the invoker.

  4. The cloud events headers must be sent via HTTP headers.

次のステップ

Google Cloud FunctionsのJAX-RS、Servlet、Vert.xのサポートを探しているなら、 Google Cloud Functions HTTP binding が存在します。