このページを編集

Funqy Google Cloud Functions

preview

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

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

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

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

前提条件

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

Google Cloud にログイン

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

gcloud auth login

クイックスタート

git clone https://github.com/quarkusio/quarkus-quickstarts.git で Git リポジトリーをクローンします。または、https://github.com/quarkusio/quarkus-quickstarts/archive/main.zip[アーカイブ] をダウンロードします。

ソリューションは 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のインストールと使用方法の詳細については、 Quarkus CLI ガイドを参照してください。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.38.3: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 オプションを追加します。

Windowsユーザーの場合:

  • cmdを使用する場合、(バックスラッシュ \ を使用せず、すべてを同じ行に書かないでください)。

  • Powershellを使用する場合は、 -D パラメータを二重引用符で囲んでください。例: "-DprojectArtifactId=funqy-google-cloud-functions"

コード

このコードには何も特別なものはありません。また、重要なこととして、Google Cloud に特化したものは何もありません。Funqy 関数はさまざまな環境にデプロイすることができ、Google Cloud Functions はそのうちの 1 つです。

Cloud Functions の関数を選択する

Google Cloud Functions のデプロイごとにエクスポートできる Funqy 関数は 1 つだけです。プロジェクト内に @Funq でアノテーションされたメソッドが 1 つしかない場合は、心配ありません。プロジェクト内に複数の関数が定義されている場合は、Quarkus application.properties 内で関数を選択する必要があります。

quarkus.funqy.export=greet

あるいは、 gcloud cliを使って Google Cloud Function を作成する際に、環境変数 QUARKUS_FUNQY_EXPORT を設定することもできます。

ビルドとデプロイ

プロジェクトのビルド

CLI
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

これでコードがコンパイルされ、パッケージ化されます。

関数の作成

この例では、2 つのバックグラウンド関数とcloud events functionを作成します。バックグラウンド関数は、PubSub メッセージ、Cloud Storage イベント、Firestore イベントなどの Google Cloud eventに対応することができます。cloud events functionを使用すると、Cloud Events 仕様を使用して、サポートされているイベントに対応できます。

import jakarta.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"));
    }
}
Function return type can also be Mutiny reactive types.
  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() メソッドがイベントの内容(この場合はストレージイベント)を返します。

we provide convenience class to deserialize common Google Cloud events inside the io.quarkus.funqy.gcp.functions.event package. They are not mandatory to use, you can use any object you want.

プロジェクトには複数の関数が含まれているので、どの関数をデプロイする必要があるかを application.properties 内の以下のプロパティーから指定する必要があります:

quarkus.funqy.export=helloPubSubWorld

アプリケーションのビルドと Google Cloud へのデプロイ

アプリケーションをビルドするには、 mvn clean package からアプリケーションをパッケージ化することができます。 target/deployment リポジトリー内には、クラスとすべての依存関係が含まれた単一の JAR があります。

これで、 gcloud を使って関数を Google Cloud にデプロイすることができるようになります。 gcloud コマンドは、どのイベントが関数のトリガーになるかによって異なります。

We will use the Java 21 runtime, but you can switch to the Java 17 runtime by using --runtime=java17 instead of --runtime=java21 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=java21 --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=java21 --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 - クラウドストレージ

関数をデプロイする前に、バケットを作成する必要があります。

gsutil mb gs://quarkus-hello

そして、このコマンドを使って Google Cloud Functions にデプロイします。

gcloud functions deploy quarkus-example-cloud-event \
  --entry-point=io.quarkus.funqy.gcp.functions.FunqyCloudEventsFunction \
  --runtime=java21 --trigger-bucket=example-cloud-event --source=target/deployment

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

--trigger-bucket= オプションは、Cloud Storage バケットの名称を定義します。

イベントをトリガーするために、GCS example-cloud-event のバケットにファイルを送信することができます。

ローカルでの実行

関数をローカルで実行する最も簡単な方法は、Cloud Function invoker JAR を使用することです。

以下のコマンドで Maven 経由でダウンロードできます。

mvn dependency:copy \
    -Dartifact='com.google.cloud.functions.invoker:java-function-invoker:2.0.0' \
    -DoutputDirectory=.

invokerを使用する前に、まず、以下のように関数をビルドする必要があります。

CLI
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

その後、これは、ローカルで関数を起動するために使用することができます。このコマンドは、関数の種類とイベントの種類に依存します。

バックグラウンド関数 - PubSub

バックグラウンド関数の場合は、 io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction のターゲットクラスで invoker を起動します。

java -jar java-function-invoker-2.0.0.jar \
  --classpath target/funqy-google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
  --target io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
The --classpath parameter needs to be set to the previously packaged JAR that contains your function class and all Quarkus related classes.

起動後、HTTP 呼び出しにイベントを含むペイロードを付与することでバックグラウンド関数を呼び出すことができます。

curl localhost:8080 -d '{"data":{"data":"world"}}'

これは、PubSub のバックグラウンド関数を PubSubMessage で呼び出します {"data":"hello”}

バックグラウンド関数 - クラウドストレージ

バックグラウンド関数の場合は、 io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction のターゲットクラスで invoker を起動します。

java -jar java-function-invoker-2.0.0.jar \
  --classpath target/funqy-google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
  --target io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
The --classpath parameter needs to be set to the previously packaged JAR that contains your function class and all Quarkus related classes.

起動後、HTTP 呼び出しにイベントを含むペイロードを付与することでバックグラウンド関数を呼び出すことができます。

curl localhost:8080 -d '{"data":{"name":"text"}}'

これは、Cloud Storage のイベント {"name":"file.txt"} (file.txt ファイル上のイベント) で PubSub のバックグラウンド関数を呼び出します。

Cloud Events Functions - クラウドストレージ

cloud events functionsの場合は、 io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction をターゲットクラスとして invoker を起動します。

java -jar java-function-invoker-2.0.0.jar \
  --classpath target/funqy-google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
  --target io.quarkus.funqy.gcp.functions.FunqyCloudEventsFunction
The --classpath parameter needs to be set to the previously packaged JAR that contains your function class and all Quarkus related classes.

起動後、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が呼び出されます。

関数のテスト

Quarkusは、 quarkus-test-google-cloud-functions の依存関係を介してFunqy Google Cloud functions をテストするためのサポートを提供しています。

これを使用するには、 pom.xml に以下のテスト依存関係を追加する必要があります。

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-test-google-cloud-functions</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured</artifactId>
    <scope>test</scope>
</dependency>

このエクステンションは、 @QuarkusTest のテストケースに、テストケースの前に Cloud Function invoker を起動し、終了時に停止するためのアノテーションとして使用できる @WithFunction アノテーションを提供します。このアノテーションは、起動したい関数のタイプと、アプリケーション内に複数の関数がある場合は関数の名前をオプションで設定する必要があります。

デフォルトのQuarkusテストポート設定 ( quarkus.http.test-port ) が優先され、0に設定するとランダムなポートが関数呼び出し元に割り当てられます。

バックグラウンド関数 - 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. これは標準的なQuarkusのテストであり、 @QuarkusTest によってアノテーションを付ける必要があります。

  2. @WithFunction(FunctionType.FUNQY_BACKGROUND) は、Funqyのバックグラウンド関数としてその関数を起動することを示します。同じアプリケーションに複数の関数が存在する場合、 functionName 属性を使用して、どの関数を起動させるかを示す必要があります。

  3. REST-assuredは関数のテストに使用され、 {"data":"world"} が、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. これは標準的なQuarkusのテストであり、 @QuarkusTest によってアノテーションを付ける必要があります。

  2. @WithFunction(FunctionType.FUNQY_BACKGROUND) は、Funqyのバックグラウンド関数としてその関数を起動することを示します。同じアプリケーションに複数の関数が存在する場合、 functionName 属性を使用して、どの関数を起動させるかを示す必要があります。

  3. REST-assuredは関数のテストに使用されます。 {"name":"hello.txt"} はinvokerを介して送られます。

Cloud Events Functions - クラウドストレージ

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. これは標準的なQuarkusのテストであり、 @QuarkusTest によってアノテーションを付ける必要があります。

  2. @WithFunction(FunctionType.FUNQY_CLOUD_EVENTS) は、その関数を Funqy クラウドイベント関数として起動することを示します。同じアプリケーションに複数の機能が存在する場合、 functionName 属性を使用して、どの関数を起動させるかを示す必要があります。

  3. REST-assuredは関数のテストに使用され、ストレージイベントを記述したこのペイロードがinvokerを介して送信されます。

  4. クラウドイベントヘッダーは、HTTPヘッダで送信する必要があります。

What’s next?

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

関連コンテンツ