Funqy Google Cloud Functions
本指南将介绍快速入门代码,向你展示如何将 Funqy 函数部署到 Google Cloud Functions。 :iokays-category: quarkus :iokays-path: modules/ROOT/pages/_includes/extension-status.adoc :keywords: Quarkus, 中文文档, 编程技术
该技术被认为是 {extension-status}。 有关可能状态的完整列表,请查看我们的 FAQ entry. |
Prerequisites
如要完成本指南,您需要:
-
Roughly 15 minutes
-
An IDE
-
安装了 JDK 17+,已正确配置
JAVA_HOME
-
Apache Maven ${proposed-maven-version}
-
如果你想使用 Quarkus CLI, 则可以选择使用
-
如果你想构建一个本机可执行文件(或如果你使用本机容器构建,则使用 Docker),则可以选择安装 Mandrel 或 GraalVM 以及 configured appropriately
The Quickstart
克隆 Git 存储库: git clone $${quickstarts-base-url}.git
,或下载 $${quickstarts-base-url}/archive/main.zip[存档]。
该解决方案位于 funqy-google-cloud-functions-quickstart
directory 中。
Creating the Maven Deployment Project
使用 quarkus-funqy-google-cloud-functions
扩展创建应用程序。你可以使用以下 Maven 命令创建它:
quarkus create app {create-app-group-id}:{create-app-artifact-id} \
--no-code
cd {create-app-artifact-id}
要创建一个 Gradle 项目,添加 --gradle
或 --gradle-kotlin-dsl
选项。
有关如何安装和使用 Quarkus CLI 的详细信息,请参见 Quarkus CLI 指南。
mvn {quarkus-platform-groupid}:quarkus-maven-plugin:{quarkus-version}:create \
-DprojectGroupId={create-app-group-id} \
-DprojectArtifactId={create-app-artifact-id} \
-DnoCode
cd {create-app-artifact-id}
要创建一个 Gradle 项目,添加 -DbuildTool=gradle
或 -DbuildTool=gradle-kotlin-dsl
选项。
适用于 Windows 用户:
-
如果使用 cmd,(不要使用反斜杠
\
,并将所有内容放在同一行上) -
如果使用 Powershell,将
-D
参数用双引号引起来,例如"-DprojectArtifactId={create-app-artifact-id}"
Choose Your Function
每个 Google Cloud Functions 部署只能导出一个 Funqy 函数。如果你在项目中只有一个使用 @Funq
进行注释的方法,那么不必担心。如果你在项目中定义了多个函数,那么你将需要在你 Quarkus application.properties
中选择该函数:
quarkus.funqy.export=greet
或者,你可以在使用 gcloud
cli 创建 Google Cloud Function 时设置 QUARKUS_FUNQY_EXPORT
环境变量。
Creating the functions
在此示例中,我们将创建两个后台函数和一个云事件函数。后台函数允许你对 Google Cloud 事件做出反应,如 PubSub 信息、Cloud Storage 事件、Firestore 事件……云事件函数允许你使用云事件规范对受支持的事件做出反应。
Quarkus 支持 Cloud Functions gen 1 和 gen 2。有关 Cloud Functions gen 2 的概述,请参阅 Google Cloud Functions 文档上的 this page。要使用 gen 2,您必须添加 |
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"));
}
}
函数返回类型还可以是 Mutiny 响应类型。 |
-
注入在您的函数内部运作。
-
这是一个将
io.quarkus.funqy.gcp.functions.event.PubsubMessage
作为参数的后台函数,这是一个用来反序列化 PubSub 消息的便捷类。 -
这是一个将
io.quarkus.funqy.gcp.functions.event.StorageEvent
作为参数的后台函数,这是一个用来反序列化 Google Storage 事件的便捷类。 -
这是一个云事件函数,它将
io.cloudevents.CloudEvent
作为参数,其中getData()
方法将返回事件内容,在本例中为存储事件。
我们在 |
由于我们的项目包含多个函数,我们需要在 application.properties
中通过以下属性指定需要部署的函数:
quarkus.funqy.export=helloPubSubWorld
Build and Deploy to Google Cloud
要构建应用程序,您可以通过 mvn clean package
打包应用程序。您将在 target/deployment
仓库中拥有一个 JAR,其中包含您的类及其所有依赖。
然后,您将可以使用 gcloud
将您的函数部署到 Google Cloud。gcloud
命令将根据触发函数的事件而有所不同。
我们将使用 Java 17 运行时,但你可以通过在部署命令中使用 |
首次启动 gcloud 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 尚未激活。要解决此错误,请打开错误中显示的网址,按照说明操作,然后等待几分钟再重试该命令。
Background Functions - 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
入口点始终需要是 io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
,因为该类将引导 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 的消息。
Background Functions - Cloud Storage
在部署函数之前,你需要创建一个存储存储区。
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
入口点始终需要是 io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
,因为该类将引导 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"}'
选项允许指定伪造的文件名,将为此名称创建伪造的 Cloud Storage 事件。
您也可以使用命令行或 Web 控制台将文件添加到 Cloud Storage。
Cloud Events Functions - Cloud Storage
Cloud Events 函数仅是 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
入口点始终需要是 io.quarkus.funqy.gcp.functions.FunqyCloudEventsFunction
,因为该类将引导 Quarkus。
@1 选项定义了 Cloud Storage 存储分区名称。
要触发事件,你可以向 GCS `example-cloud-event`存储存储区发送一个文件。
Running locally
本地运行函数的最简单方法是使用 Cloud Function Invoker JAR。
你可以使用以下命令通过 Maven 下载它:
mvn dependency:copy \
-Dartifact='com.google.cloud.functions.invoker:java-function-invoker:{gcf-invoker-version}' \
-DoutputDirectory=.
使用 invoker 之前,您首先需要通过以下方式构建您的函数:
quarkus build
./mvnw install
./gradlew build
然后,你可以用它在本地启动你的函数,同样,该命令取决于函数的类型和事件的类型。
Background Functions - PubSub
对于基于时间的函数,你可以使用目标类 @2 启动调用程序。
java -jar java-function-invoker-{gcf-invoker-version}.jar \
--classpath target/funqy-google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
--target io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
`--classpath`参数需要设置为先前打包的 JAR,其中包含您的函数类和所有 Quarkus 相关类。
然后,您可以通过 HTTP 调用(其包含事件的有效负载)来调用您的 background 函数:
curl localhost:8080 -d '{"data":{"data":"world"}}'
这会使用 PubSubMessage @3 使用一个 PubSub 背景函数调用你的 PubSub 背景函数。
Background Functions - Cloud Storage
对于基于时间的函数,你可以使用目标类 @2 启动调用程序。
java -jar java-function-invoker-{gcf-invoker-version}.jar \
--classpath target/funqy-google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
--target io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
`--classpath`参数需要设置为先前打包的 JAR,其中包含您的函数类和所有 Quarkus 相关类。
然后,您可以通过 HTTP 调用(其包含事件的有效负载)来调用您的 background 函数:
curl localhost:8080 -d '{"data":{"name":"text"}}'
这会使用一个 Cloud Storage 事件 @4 调用你的 PubSub 背景函数,也就是一个 @5 文件的事件。
Cloud Events Functions - Cloud Storage
Cloud Events 函数仅是 Cloud Functions gen 2 的一项功能。
对于基于云的事件函数,你可以使用目标类 @6 启动调用程序。
java -jar java-function-invoker-{gcf-invoker-version}.jar \
--classpath target/funqy-google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
--target io.quarkus.funqy.gcp.functions.FunqyCloudEventsFunction
`--classpath`参数需要设置为先前打包的 JAR,其中包含您的函数类和所有 Quarkus 相关类。
然后,您可以通过 HTTP 调用(其包含事件的有效负载)来调用您的 background 函数:
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`文件上的事件调用您的云事件函数。
Testing your function
Quarkus 借助 @7 依赖项提供内置支持,可用来测试你的 Funqy Google Cloud 函数。
要使用它,您必须在 `pom.xml`中添加以下测试依赖项。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-google-cloud-functions</artifactId>
<scope>test</scope>
</dependency>
此扩展提供了 `@WithFunction`注释,该注释可用于注释 `@QuarkusTest`测试用例,以便在测试用例之前启动 Cloud Function invoker 并在此类结束之后停止它。必须使用您想要启动的函数的类型来配置此注释,还可以选择函数的名称(如果您在应用程序中有多个函数)。
将尊重默认 Quarkus 测试端口配置 (quarkus.http.test-port
),如果您将它设置为 0,则会将一个随机端口分配给函数 invoker。
Background Functions - 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);
}
}
-
这是必须由 `@QuarkusTest`注释的标准 Quarkus 测试。
-
@8 指示将该函数作为 Funqy 背景函数启动。如果同一应用程序中存在多个函数,则必须使用 @9 属性来表示应当启动哪一个。
-
REST-assured 用于测试函数,将通过调用器将 @10 发送给它。
Background Functions - Cloud Storage
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);
}
}
-
这是必须由 `@QuarkusTest`注释的标准 Quarkus 测试。
-
@8 指示将该函数作为 Funqy 背景函数启动。如果同一应用程序中存在多个函数,则必须使用 @9 属性来表示应当启动哪一个。
-
REST-assured 用于测试函数,`{"name":"hello.txt"}`将通过调用器发送到该函数。
Cloud Events Functions - Cloud Storage
Cloud Events 函数仅是 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);
}
}
-
这是必须由 `@QuarkusTest`注释的标准 Quarkus 测试。
-
@11 表示将该函数作为 Funqy 云事件函数启动。如果同一应用程序中存在多个函数,则必须使用 @12 属性来表示应当启动哪一个。
-
REST-assured 用于测试函数,通过调用器将描述存储事件的此有效负载发送到该函数。
-
Cloud Events 标头必须通过 HTTP 标头发送。
What’s next?
如果您正在为 Google Cloud Functions 寻找 Jakarta REST、Servlet 或 Vert.x 支持,我们已经使用Google Cloud Functions HTTP binding实现了该支持。