Funqy Google Cloud Functions
本指南将引导您通过快速入门代码,向您展示如何将 Funqy 函数部署到 Google Cloud Functions。
此技术被认为是预览版。 在预览版中,不保证向后兼容性和在生态系统中的存在。 具体改进可能需要更改配置或 API,成为稳定版的计划正在进行中。 欢迎通过我们的邮件列表或在我们的 GitHub 问题跟踪器中提出反馈。 有关可能的完整状态列表,请查看我们的常见问题解答条目。 |
先决条件
要完成本指南,您需要
-
大约 30 分钟
-
一个 IDE
-
已安装 JDK 17+ 并正确配置了
JAVA_HOME
-
Apache Maven 3.9.9
-
如果您想使用它,可以选择 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 命令来创建它
对于 Windows 用户
-
如果使用 cmd,(不要使用反斜杠
\
并将所有内容放在同一行上) -
如果使用 Powershell,请将
-D
参数用双引号括起来,例如"-DprojectArtifactId=funqy-google-cloud-functions"
选择您的函数
每个 Google Cloud Functions 部署只能导出一个 Funqy 函数。 如果您的项目中只有一个使用 @Funq
注释的方法,则无需担心。 如果您在项目中定义了多个函数,则需要在 Quarkus application.properties
中选择该函数
quarkus.funqy.export=greet
或者,您可以使用 gcloud
cli 创建 Google Cloud Function 时设置 QUARKUS_FUNQY_EXPORT
环境变量。
创建函数
在此示例中,我们将创建两个后台函数和一个云事件函数。 后台函数允许您对 Google Cloud 事件(如 PubSub 消息、Cloud Storage 事件、Firestore 事件等)做出反应。云事件函数允许您使用 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"));
}
}
函数返回类型也可以是 Mutiny 反应式类型。 |
-
注入在您的函数内部起作用。
-
这是一个后台函数,它将
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。
然后您就可以使用 gcloud
将您的函数部署到 Google Cloud。 gcloud
命令将根据触发您的函数的事件而有所不同。
我们将使用 Java 21 运行时,但您可以通过在部署命令中使用 --runtime=java17 而不是 --runtime=java21 来切换到 Java 17 运行时。 |
首次启动
这意味着 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
入口点始终需要是 |
--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 的消息。
后台函数 - 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=java21 --trigger-resource quarkus-hello --trigger-event google.storage.object.finalize \
--source=target/deployment
入口点始终需要是 |
--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 Storage
在部署您的函数之前,您需要创建一个存储桶。
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
入口点始终需要是 |
--trigger-bucket=
选项定义 Cloud Storage 存储桶的名称。
要触发事件,您可以将文件发送到 GCS example-cloud-event
存储桶。
本地运行
在本地运行您的函数的最简单方法是使用 Cloud Function 调用器 JAR。
您可以使用以下命令通过 Maven 下载它
mvn dependency:copy \
-Dartifact='com.google.cloud.functions.invoker:java-function-invoker:1.4.1' \
-DoutputDirectory=.
在使用调用器之前,您首先需要通过以下方式构建您的函数
quarkus build
./mvnw install
./gradlew build
然后您可以使用它在本地启动您的函数,同样,该命令取决于函数的类型和事件的类型。
后台函数 - PubSub
对于后台函数,您可以使用 io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
的目标类启动调用器。
java -jar java-function-invoker-1.4.1.jar \
--classpath target/funqy-google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
--target io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
--classpath 参数需要设置为先前打包的 JAR,其中包含您的函数类和所有 Quarkus 相关类。 |
然后,您可以通过包含事件有效负载的 HTTP 调用来调用您的后台函数
curl localhost:8080 -d '{"data":{"data":"world"}}'
这将使用 PubSubMessage {"data":"hello"}
调用您的 PubSub 后台函数。
后台函数 - Cloud Storage
对于后台函数,您可以使用 io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
的目标类启动调用器。
java -jar java-function-invoker-1.4.1.jar \
--classpath target/funqy-google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
--target io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
--classpath 参数需要设置为先前打包的 JAR,其中包含您的函数类和所有 Quarkus 相关类。 |
然后,您可以通过包含事件有效负载的 HTTP 调用来调用您的后台函数
curl localhost:8080 -d '{"data":{"name":"text"}}'
这将使用 Cloud Storage 事件 {"name":"file.txt"}
调用您的 PubSub 后台函数,因此是关于 file.txt
文件的事件。
云事件函数 - Cloud Storage
对于云事件函数,您可以使用 io.quarkus.funqy.gcp.functions.FunqyCloudEventsFunction`
的目标类启动调用器。
java -jar java-function-invoker-1.4.1.jar \
--classpath target/funqy-google-cloud-functions-1.0.0-SNAPSHOT-runner.jar \
--target io.quarkus.funqy.gcp.functions.FunqyCloudEventsFunction
--classpath 参数需要设置为先前打包的 JAR,其中包含您的函数类和所有 Quarkus 相关类。 |
然后,您可以通过包含事件有效负载的 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
文件上的事件调用您的云事件函数。
测试您的函数
Quarkus 通过 quarkus-test-google-cloud-functions
依赖项为测试您的 Funqy Google Cloud 函数提供内置支持。
要使用它,您必须在您的 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>
此扩展提供了一个 @WithFunction
注释,可用于注释 @QuarkusTest
测试用例,以在测试用例之前启动 Cloud Function 调用器,并在结束时停止它。 此注释必须配置为您要启动的函数的类型,并且可以选择函数的名称,以防您的应用程序中包含多个函数。
默认的 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);
}
}
-
这是一个标准的 Quarkus 测试,必须通过
@QuarkusTest
注释。 -
@WithFunction(FunctionType.FUNQY_BACKGROUND)
指示将函数作为 Funqy 后台函数启动。 如果同一应用程序中存在多个函数,则必须使用functionName
属性来表示应启动哪个函数。 -
REST-assured 用于测试该函数,
{"data":"world"}
将通过调用器发送给它。
后台函数 - 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);
}
}
-
这是一个标准的 Quarkus 测试,必须通过
@QuarkusTest
注释。 -
@WithFunction(FunctionType.FUNQY_BACKGROUND)
指示将函数作为 Funqy 后台函数启动。 如果同一应用程序中存在多个函数,则必须使用functionName
属性来表示应启动哪个函数。 -
REST-assured 用于测试该函数,
{"name":"hello.txt"}
将通过调用器发送给它。
云事件函数 - 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_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);
}
}
-
这是一个标准的 Quarkus 测试,必须通过
@QuarkusTest
注释。 -
@WithFunction(FunctionType.FUNQY_CLOUD_EVENTS)
指示将函数作为 Funqy 云事件函数启动。 如果同一应用程序中存在多个函数,则必须使用functionName
属性来表示应启动哪个函数。 -
REST-assured 用于测试该函数,描述存储事件的有效负载将通过调用器发送给它。
-
云事件标头必须通过 HTTP 标头发送。
下一步是什么?
如果您正在寻找对 Google Cloud Functions 的 Jakarta REST、Servlet 或 Vert.x 支持,我们通过我们的 Google Cloud Functions HTTP 绑定提供了支持。