Cloud Pub/Sub 教程(第 2 代)


本简易教程演示了如何使用 Cloud Pub/Sub 触发器编写、部署和触发 Cloud Functions 事件驱动函数

如果您刚接触 Pub/Sub,并且希望了解详情,请参阅 Pub/Sub 文档,特别是管理主题和订阅。如需简要了解如何在 Cloud Functions 中处理 Pub/Sub 主题和订阅,请参阅 Google Cloud Pub/Sub 触发器

如果您要查找使用 Pub/Sub 本身的代码示例,请访问 Google Cloud 示例浏览器

目标

费用

在本文档中,您将使用 Google Cloud 的以下收费组件:

  • Cloud Functions
  • Cloud Build
  • Pub/Sub
  • Artifact Registry
  • Eventarc
  • Cloud Logging

如需了解详情,请参阅 Cloud Functions 价格

您可使用价格计算器根据您的预计使用情况来估算费用。 Google Cloud 新用户可能有资格申请免费试用

准备工作

  1. 登录您的 Google Cloud 账号。如果您是 Google Cloud 新手,请创建一个账号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. 确保您的 Google Cloud 项目已启用结算功能

  4. Enable the Cloud Functions, Cloud Build, Artifact Registry, Eventarc, Logging, and Pub/Sub APIs.

    Enable the APIs

  5. Install the Google Cloud CLI.
  6. To initialize the gcloud CLI, run the following command:

    gcloud init
  7. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  8. 确保您的 Google Cloud 项目已启用结算功能

  9. Enable the Cloud Functions, Cloud Build, Artifact Registry, Eventarc, Logging, and Pub/Sub APIs.

    Enable the APIs

  10. Install the Google Cloud CLI.
  11. To initialize the gcloud CLI, run the following command:

    gcloud init
  12. 如果您已经安装 gcloud CLI,请运行以下命令进行更新:

    gcloud components update
  13. 准备开发环境。

前提条件

创建 Pub/Sub 主题:

gcloud pubsub topics create YOUR_TOPIC_NAME

这是部署函数之前必须执行的步骤。在 Cloud Functions(第 2 代)中,部署函数时不会自动创建 Pub/Sub 主题。

准备应用

  1. 将示例应用代码库克隆到本地机器:

    Node.js

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    或者,您也可以下载该示例的 zip 文件并将其解压缩。

    Python

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

    或者,您也可以下载该示例的 zip 文件并将其解压缩。

    Go

    git clone https://github.com/GoogleCloudPlatform/golang-samples.git

    或者,您也可以下载该示例的 zip 文件并将其解压缩。

    Java

    git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git

    或者,您也可以下载该示例的 zip 文件并将其解压缩。

    C#

    git clone https://github.com/GoogleCloudPlatform/dotnet-docs-samples.git

    或者,您也可以下载该示例的 zip 文件并将其解压缩。

    Ruby

    git clone https://github.com/GoogleCloudPlatform/ruby-docs-samples.git

    或者,您也可以下载该示例的 zip 文件并将其解压缩。

    PHP

    git clone https://github.com/GoogleCloudPlatform/php-docs-samples.git

    或者,您也可以下载该示例的 zip 文件并将其解压缩。

  2. 切换到包含用于访问 Pub/Sub 的 Cloud Functions 函数示例代码的目录:

    Node.js

    cd nodejs-docs-samples/functions/v2/helloPubSub/

    Python

    cd python-docs-samples/functions/v2/pubsub/

    Go

    cd golang-samples/functions/functionsv2/hellopubsub/

    Java

    cd java-docs-samples/functions/v2/pubsub/

    C#

    cd dotnet-docs-samples/functions/helloworld/HelloPubSub/

    Ruby

    cd ruby-docs-samples/functions/helloworld/pubsub/

    PHP

    cd php-docs-samples/functions/helloworld_pubsub/

  3. 查看示例代码:

    Node.js

    const functions = require('@google-cloud/functions-framework');
    
    // Register a CloudEvent callback with the Functions Framework that will
    // be executed when the Pub/Sub trigger topic receives a message.
    functions.cloudEvent('helloPubSub', cloudEvent => {
      // The Pub/Sub message is passed as the CloudEvent's data payload.
      const base64name = cloudEvent.data.message.data;
    
      const name = base64name
        ? Buffer.from(base64name, 'base64').toString()
        : 'World';
    
      console.log(`Hello, ${name}!`);
    });

    Python

    import base64
    
    from cloudevents.http import CloudEvent
    import functions_framework
    
    # Triggered from a message on a Cloud Pub/Sub topic.
    @functions_framework.cloud_event
    def subscribe(cloud_event: CloudEvent) -> None:
        # Print out the data from Pub/Sub, to prove that it worked
        print(
            "Hello, " + base64.b64decode(cloud_event.data["message"]["data"]).decode() + "!"
        )
    
    

    Go

    
    // Package helloworld provides a set of Cloud Functions samples.
    package helloworld
    
    import (
    	"context"
    	"fmt"
    	"log"
    
    	"github.com/GoogleCloudPlatform/functions-framework-go/functions"
    	"github.com/cloudevents/sdk-go/v2/event"
    )
    
    func init() {
    	functions.CloudEvent("HelloPubSub", helloPubSub)
    }
    
    // MessagePublishedData contains the full Pub/Sub message
    // See the documentation for more details:
    // https://cloud.google.com/eventarc/docs/cloudevents#pubsub
    type MessagePublishedData struct {
    	Message PubSubMessage
    }
    
    // PubSubMessage is the payload of a Pub/Sub event.
    // See the documentation for more details:
    // https://cloud.google.com/pubsub/docs/reference/rest/v1/PubsubMessage
    type PubSubMessage struct {
    	Data []byte `json:"data"`
    }
    
    // helloPubSub consumes a CloudEvent message and extracts the Pub/Sub message.
    func helloPubSub(ctx context.Context, e event.Event) error {
    	var msg MessagePublishedData
    	if err := e.DataAs(&msg); err != nil {
    		return fmt.Errorf("event.DataAs: %w", err)
    	}
    
    	name := string(msg.Message.Data) // Automatically decoded from base64.
    	if name == "" {
    		name = "World"
    	}
    	log.Printf("Hello, %s!", name)
    	return nil
    }
    

    Java

    import com.google.cloud.functions.CloudEventsFunction;
    import com.google.gson.Gson;
    import functions.eventpojos.PubSubBody;
    import io.cloudevents.CloudEvent;
    import java.nio.charset.StandardCharsets;
    import java.util.Base64;
    import java.util.logging.Logger;
    
    public class SubscribeToTopic implements CloudEventsFunction {
      private static final Logger logger = Logger.getLogger(SubscribeToTopic.class.getName());
    
      @Override
      public void accept(CloudEvent event) {
        // The Pub/Sub message is passed as the CloudEvent's data payload.
        if (event.getData() != null) {
          // Extract Cloud Event data and convert to PubSubBody
          String cloudEventData = new String(event.getData().toBytes(), StandardCharsets.UTF_8);
          Gson gson = new Gson();
          PubSubBody body = gson.fromJson(cloudEventData, PubSubBody.class);
          // Retrieve and decode PubSub message data
          String encodedData = body.getMessage().getData();
          String decodedData =
              new String(Base64.getDecoder().decode(encodedData), StandardCharsets.UTF_8);
          logger.info("Hello, " + decodedData + "!");
        }
      }
    }

    C#

    using CloudNative.CloudEvents;
    using Google.Cloud.Functions.Framework;
    using Google.Events.Protobuf.Cloud.PubSub.V1;
    using Microsoft.Extensions.Logging;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace HelloPubSub;
    
    public class Function : ICloudEventFunction<MessagePublishedData>
    {
        private readonly ILogger _logger;
    
        public Function(ILogger<Function> logger) =>
            _logger = logger;
    
        public Task HandleAsync(CloudEvent cloudEvent, MessagePublishedData data, CancellationToken cancellationToken)
        {
            string nameFromMessage = data.Message?.TextData;
            string name = string.IsNullOrEmpty(nameFromMessage) ? "world" : nameFromMessage;
            _logger.LogInformation("Hello {name}", name);
            return Task.CompletedTask;
        }
    }

    Ruby

    require "functions_framework"
    require "base64"
    
    FunctionsFramework.cloud_event "hello_pubsub" do |event|
      # The event parameter is a CloudEvents::Event::V1 object.
      # See https://cloudevents.github.io/sdk-ruby/latest/CloudEvents/Event/V1.html
      name = Base64.decode64 event.data["message"]["data"] rescue "World"
    
      # A cloud_event function does not return a response, but you can log messages
      # or cause side effects such as sending additional events.
      logger.info "Hello, #{name}!"
    end

    PHP

    
    use CloudEvents\V1\CloudEventInterface;
    use Google\CloudFunctions\FunctionsFramework;
    
    // Register the function with Functions Framework.
    // This enables omitting the `FUNCTIONS_SIGNATURE_TYPE=cloudevent` environment
    // variable when deploying. The `FUNCTION_TARGET` environment variable should
    // match the first parameter.
    FunctionsFramework::cloudEvent('helloworldPubsub', 'helloworldPubsub');
    
    function helloworldPubsub(CloudEventInterface $event): void
    {
        $log = fopen(getenv('LOGGER_OUTPUT') ?: 'php://stderr', 'wb');
    
        $cloudEventData = $event->getData();
        $pubSubData = base64_decode($cloudEventData['message']['data']);
    
        $name = $pubSubData ? htmlspecialchars($pubSubData) : 'World';
        fwrite($log, "Hello, $name!" . PHP_EOL);
    }

部署函数

如需部署带有 Pub/Sub 触发器的函数,请在包含示例代码(如果是 Java,则为 pom.xml 文件)的目录中运行以下命令:

// LINT.IfChange(nodejs_version) // LINT.ThenChange(:nodejs_version_console_text) // LINT.IfChange(nodejs_version_console_text) // LINT.ThenChange(:nodejs_version) // LINT.IfChange(nodejs_version) // LINT.ThenChange(:nodejs_version_console_text) // LINT.IfChange(nodejs_version_console_text) // LINT.ThenChange(:nodejs_version)

Node.js

gcloud functions deploy nodejs-pubsub-function \
--gen2 \
--runtime=nodejs20 \
--region=REGION \
--source=. \
--entry-point=helloPubSub \
--trigger-topic=YOUR_TOPIC_NAME

使用 --runtime 标志可以指定支持的 Node.js 版本的运行时 ID 来运行您的函数。

Python

gcloud functions deploy python-pubsub-function \
--gen2 \
--runtime=python312 \
--region=REGION \
--source=. \
--entry-point=subscribe \
--trigger-topic=YOUR_TOPIC_NAME

使用 --runtime 标志可以指定支持的 Python 版本的运行时 ID 来运行您的函数。

Go

gcloud functions deploy go-pubsub-function \
--gen2 \
--runtime=go121 \
--region=REGION \
--source=. \
--entry-point=HelloPubSub \
--trigger-topic=YOUR_TOPIC_NAME

使用 --runtime 标志可以指定支持的 Go 版本的运行时 ID 来运行您的函数。

Java

gcloud functions deploy java-pubsub-function \
--gen2 \
--runtime=java17 \
--region=REGION \
--source=. \
--entry-point=functions.SubscribeToTopic \
--memory=512MB \
--trigger-topic=YOUR_TOPIC_NAME

使用 --runtime 标志可以指定支持的 Java 版本的运行时 ID 来运行您的函数。

C#

gcloud functions deploy csharp-pubsub-function \
--gen2 \
--runtime=dotnet6 \
--region=REGION \
--source=. \
--entry-point=HelloPubSub.Function \
--trigger-topic=YOUR_TOPIC_NAME

使用 --runtime 标志可以指定支持的 .NET 版本的运行时 ID 来运行您的函数。

Ruby

gcloud functions deploy ruby-pubsub-function \
--gen2 \
--runtime=ruby32 \
--region=REGION \
--source=. \
--entry-point=hello_pubsub \
-
-trigger-topic=YOUR_TOPIC_NAME

使用 --runtime 标志可以指定支持的 Ruby 版本的运行时 ID 来运行您的函数。

PHP

gcloud functions deploy php-pubsub-function \
--gen2 \
--runtime=php82 \
--region=REGION \
--source=. \
--entry-point=helloworldPubsub \
-
-trigger-topic=YOUR_TOPIC_NAME

使用 --runtime 标志可以指定支持的 PHP 版本的运行时 ID 来运行您的函数。

其中,YOUR_TOPIC_NAME 是函数将订阅的 Pub/Sub 主题的名称。

在运行 deploy 命令之前,您必须先使用 Google Cloud 控制台gcloud 命令行工具创建主题。与 Cloud Functions (第 1 代) 不同,在 Cloud Functions (第 2 代) 中,使用 Pub/Sub 触发器部署函数时系统不会自动创建 Pub/Sub 主题。

触发函数

如需测试 Pub/Sub 函数,请执行以下操作:

  1. 向主题发布消息:

    gcloud pubsub topics publish my-topic --message="Friend"
    
  2. 读取函数日志以查看结果:

    gcloud functions logs read \
      --gen2 \
      --region=REGION \
      --limit=5 \
      FUNCTION_NAME
    

    请替换以下内容:

    • REGION 是部署函数的 Google Cloud 区域的名称(例如 us-west1)。
    • FUNCTION_NAME 是您在部署函数时提供的函数名称(例如,本教程中的 Node.js 函数部署时使用函数名称 nodejs-pubsub-function)。

    您应该会看到包含新的“Friend”消息的日志记录输出。

清理

为避免因本教程中使用的资源导致您的 Google Cloud 账号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。

删除项目

为了避免产生费用,最简单的方法是删除您为本教程创建的项目。

要删除项目,请执行以下操作:

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

删除 Cloud Functions 函数

删除 Cloud Functions 函数不会移除存储在 Cloud Storage 中的任何资源。

如需删除您在本教程中创建的 Cloud Functions 函数,请运行以下命令:

Node.js

gcloud functions delete nodejs-pubsub-function --gen2 --region REGION 

Python

gcloud functions delete python-pubsub-function --gen2 --region REGION 

Go

gcloud functions delete go-pubsub-function --gen2 --region REGION 

Java

gcloud functions delete java-pubsub-function --gen2 --region REGION 

C#

gcloud functions delete csharp-pubsub-function --gen2 --region REGION 

Ruby

gcloud functions delete ruby-pubsub-function --gen2 --region REGION 

PHP

gcloud functions delete php-pubsub-function --gen2 --region REGION 

您也可以通过 Google Cloud 控制台删除 Cloud Functions 函数。