你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

教程:使用事件订阅在 Blob 容器上触发 Azure Functions

以前版本的 Azure Functions Blob 存储触发器会轮询存储容器以发现更改。 最新版本的 Blob 存储扩展 (5.x+) 改为在容器上使用事件网格事件订阅。 此事件订阅通过在订阅的容器中发生更改时立即触发函数来减少延迟。

本文介绍如何创建一个函数,该函数基于将 Blob 添加到容器时引发的事件运行。 你将使用 Visual Studio Code 进行本地开发,并在将项目部署到 Azure 之前验证代码。

  • 在新项目中创建基于事件的 Blob 存储触发的函数。
  • 使用 Azurite 模拟器在 Visual Studio Code 中本地验证。
  • 在 Azure 的新存储帐户中创建 blob 存储容器。
  • 在 Flex 消耗计划(预览版)中创建函数应用。
  • 为新的 blob 容器创建事件订阅。
  • 在 Azure 中部署和验证函数代码。

本文支持适用于 Azure Functions 的 Node.js 编程模型版本 4。

本文支持适用于 Azure Functions 的 Python 编程模型版本 2。

本文创建一个在独立辅助角色模式下运行的 C# 应用,该应用支持 .NET 8.0。

重要

本教程要求使用 Flex 消耗计划(目前为预览版)。 灵活消耗计划仅支持基于事件的 Blob 存储触发器版本。

先决条件

注意

Visual Studio Code 的 Azure 存储扩展目前为预览版。

创建 Blob 触发的函数

使用 Visual Studio Code 创建 Blob 存储触发函数时,也会创建新项目。 需要编辑该函数以使用事件订阅作为源,而不是使用常规的受轮询容器。

  1. 在 Visual Studio Code 中,按 F1 打开命令面板,输入 Azure Functions: Create Function... 并选择“创建新项目”

  2. 对于项目工作区,请选择目录位置。 确保为项目工作区创建一个新文件夹或选择一个空文件夹。

    不要选择已是某个工作区的一部分的项目文件夹。

    1. 根据提示提供以下信息:
    Prompt 操作
    选择一种语言 选择 C#
    选择 .NET 运行时 选择 .NET 8.0 Isolated LTS
    为项目的第一个函数选择模板 选择 Azure Blob Storage trigger (using Event Grid)
    提供函数名称 输入 EventGridBlobTrigger
    提供命名空间 输入 My.Functions
    从“local.settings.json”中选择设置 选择 Create new local app setting
    选择订阅 根据需要选择订阅。
    选择存储帐户 使用 Azurite 模拟器进行本地存储。
    触发器将会监视的存储帐户中的路径 接受默认值 samples-workitems
    选择打开项目的方式 选择 Open in current window
    Prompt 操作
    选择一种语言 选择 Python
    选择 Python 编程模型 选择 Model V2
    选择 Python 解释器来创建虚拟环境 选择首选的 Python 解释器。 如果某个选项未显示,请输入 Python 二进制文件的完整路径。
    为项目的第一个函数选择模板 选择 Blob trigger。 (基于事件的模板尚不可用。)
    提供函数名称 输入 EventGridBlobTrigger
    触发器将会监视的存储帐户中的路径 接受默认值 samples-workitems
    从“local.settings.json”中选择设置 选择 Create new local app setting
    选择订阅 根据需要选择订阅。
    选择存储帐户 使用 Azurite 模拟器进行本地存储。
    选择打开项目的方式 选择 Open in current window
    Prompt 操作
    选择一种语言 选择 Java
    选择一个 Java 版本 选择 Java 11Java 8,即在 Azure 中运行函数且已在本地验证的 Java 版本。
    提供一个组 ID 选择 com.function
    提供一个项目 ID 选择 EventGridBlobTrigger(或默认值)。
    提供一个版本 选择 1.0-SNAPSHOT
    提供一个包名称 选择 com.function
    提供一个应用名称 接受以 EventGridBlobTrigger 开头的已生成名称。
    选择 Java 项目的生成工具 选择 Maven
    选择打开项目的方式 选择 Open in current window

    将为你创建 HTTP 触发的函数 (HttpExample)。 不会使用此函数,必须改为创建新函数。

    提示 操作
    选择函数项目的语言 选择 TypeScript
    选择 TypeScript 编程模型 选择 Model V4
    为项目的第一个函数选择模板 选择 Azure Blob Storage trigger (using Event Grid)
    提供函数名称 输入 EventGridBlobTrigger
    从“local.settings.json”中选择设置 选择 Create new local app setting
    选择订阅 根据需要选择订阅。
    选择存储帐户 使用 Azurite 模拟器进行本地存储。
    触发器将会监视的存储帐户中的路径 接受默认值 samples-workitems
    选择打开项目的方式 选择 Open in current window
    Prompt 操作
    选择函数项目的语言 选择 JavaScript
    选择 JavaScript 编程模型 选择 Model V4
    为项目的第一个函数选择模板 选择 Azure Blob Storage trigger (using Event Grid)
    提供函数名称 输入 eventGridBlobTrigger
    从“local.settings.json”中选择设置 选择 Create new local app setting
    选择订阅 根据需要选择订阅。
    选择存储帐户 使用 Azurite 模拟器进行本地存储。
    触发器将会监视的存储帐户中的路径 接受默认值 samples-workitems
    选择打开项目的方式 选择 Open in current window
    Prompt 操作
    选择函数项目的语言 选择 PowerShell
    为项目的第一个函数选择模板 选择 Azure Blob Storage trigger (using Event Grid)
    提供函数名称 输入 EventGridBlobTrigger
    从“local.settings.json”中选择设置 选择 Create new local app setting
    选择订阅 根据需要选择订阅。
    选择存储帐户 使用 Azurite 模拟器进行本地存储。
    触发器将会监视的存储帐户中的路径 接受默认值 samples-workitems
    选择打开项目的方式 选择 Open in current window
  1. 在命令面板中,输入 Azure Functions: Create Function... 并选择 EventGridBlobTrigger。 如果未看到此模板,请先选择“更改模板筛选器”>“所有”。

  2. 根据提示提供以下信息:

    Prompt 操作
    提供一个包名称 选择 com.function
    提供函数名称 输入 EventGridBlobTrigger
    从“local.settings.json”中选择设置 选择 Create new local app setting
    选择订阅 选择订阅。
    选择存储帐户 使用 Azurite 模拟器进行本地存储。
    触发器将会监视的存储帐户中的路径 接受默认值 samples-workitems

现在,你有一个函数,该函数可由 Blob 存储容器中的事件触发。

更新触发器源

首先需要将触发器源从默认 Blob 触发器源(容器轮询)切换到事件订阅源。

  1. 打开 function_app.py 项目文件,可以看到应用 blob_trigger 修饰器的函数的定义 EventGridBlobTrigger

  2. 通过添加 source = "EventGrid" 来更新修饰器。 函数现在应如下所示:

    @app.blob_trigger(arg_name="myblob", source="EventGrid", path="samples-workitems",
                               connection="<STORAGE_ACCOUNT>") 
    def EventGridBlobTrigger(myblob: func.InputStream):
    logging.info(f"Python blob trigger function processed blob"
                f"Name: {myblob.name}"
                f"Blob Size: {myblob.length} bytes")
    

    在此定义中,source = "EventGrid" 指示 samples-workitems blob 容器的事件订阅用作启动触发器的事件源。

(可选)查看代码

打开生成的 EventGridBlobTrigger.cs 文件,可以看到 EventGridBlobTrigger 函数的定义,看起来类似如下所示:

[Function(nameof(EventGridBlobTriggerCSharp))]
public async Task Run([BlobTrigger("PathValue/{name}", Source = BlobTriggerSource.EventGrid, Connection = "ConnectionValue")] Stream stream, string name)
{
    using var blobStreamReader = new StreamReader(stream);
    var content = await blobStreamReader.ReadToEndAsync();
    _logger.LogInformation($"C# Blob Trigger (using Event Grid) processed blob\n Name: {name} \n Data: {content}");
}

在此定义中,Source = BlobTriggerSource.EventGrid 指示 Blob 容器的事件订阅(在示例 PathValue 中)用作启动触发器的事件源。

打开生成的 EventGridBlobTrigger.java 文件,可以看到 EventGridBlobTrigger 函数的定义,看起来类似如下所示:

    @FunctionName("EventGridBlobTrigger")
    @StorageAccount("<STORAGE_ACCOUNT>")
    public void run(
        @BlobTrigger(name = "content", source = "EventGrid", path = "samples-workitems/{name}", dataType = "binary") byte[] content,
        @BindingName("name") String name,
        final ExecutionContext context
    ) {
        context.getLogger().info("Java Blob trigger function processed a blob. Name: " + name + "\n  Size: " + content.length + " Bytes");
    }

在此定义中,source = EventGrid 指示 samples-workitems blob 容器的事件订阅用作启动触发器的事件源。

EventGridBlobTrigger 文件夹中,打开 function.json 文件,并使用 blobTriggertypeEventGridsource 找到如下所示的绑定定义:

{
    "bindings": [
        {
            "name": "InputBlob",
            "type": "blobTrigger",
            "direction": "in",
            "path": "samples-workitems/{name}",
            "source": "EventGrid",
            "connection":""
        }
    ]
}

path 指示 samples-workitems blob 容器用作启动触发器的事件的源。

打开生成的 EventGridBlobTrigger.js 文件,可以看到函数的定义,看起来类似如下所示:

const { app } = require('@azure/functions');

app.storageBlob('storageBlobTrigger1', {
    path: 'samples-workitems/{name}',
    connection: 'MyStorageAccountAppSetting',
    source: 'EventGrid',
    handler: (blob, context) => {
        context.log(
            `Storage blob function processed blob "${context.triggerMetadata.name}" with size ${blob.length} bytes`
        );
    },
});

在此定义中,EventGridsource 指示 samples-workitems blob 容器的事件订阅用作启动触发器的事件源。

打开生成的 EventGridBlobTrigger.ts 文件,可以看到函数的定义,看起来类似如下所示:

import { app, InvocationContext } from '@azure/functions';

export async function storageBlobTrigger1(blob: Buffer, context: InvocationContext): Promise<void> {
    context.log(
        `Storage blob function processed blob "${context.triggerMetadata.name}" with size ${blob.length} bytes`
    );
}

app.storageBlob('storageBlobTrigger1', {
    path: 'samples-workitems/{name}',
    connection: 'MyStorageAccountAppSetting',
    source: 'EventGrid',
    handler: storageBlobTrigger1,
});

在此定义中,EventGridsource 指示 samples-workitems blob 容器的事件订阅用作启动触发器的事件源。

升级存储扩展

若要使用基于事件网格的 Blob 存储触发器,Azure Functions 存储扩展必须至少版本 5.x。

若要使用所需的扩展版本升级项目,请在终端窗口中运行以下 dotnet add package 命令:

dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs 
  1. 打开 host.json 项目文件并查看 extensionBundle 元素。

  2. 如果 extensionBundle.version 不是至少 3.3.0 ,请将 extensionBundle 元素替换为以下版本:

    "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[4.0.0, 5.0.0)"
    }
    

准备本地存储模拟

Visual Studio Code 在本地运行时使用 Azurite 模拟 Azure 存储服务。 在本地开发和测试期间,将使用 Azurite 模拟 Azure Blob 存储服务。

  1. 如果尚未这样做,请安装适用于 Visual Studio Code 的 Azurite v3 扩展

  2. 验证 local.settings.json 文件是否已为 AzureWebJobsStorage 设置 "UseDevelopmentStorage=true",这指示 Core Tools 在本地运行时使用 Azurite 而不是真正的存储帐户连接

  3. 按 F1 打开命令面板,键入 Azurite: Start Blob Service,然后按 Enter,将启动 Azurite Blob 存储服务模拟器。

  4. 选择活动栏中的 Azure 图标,展开“工作区”>“附加存储帐户”>“本地模拟器”,右键单击“Blob 容器”,选择“创建 Blob 容器...”,输入名称 samples-workitems,然后按 Enter

    显示如何在 Visual Studio Code 的本地模拟中选择“创建 Blob 容器”的屏幕截图。

  5. 展开“Blob 容器”>“samples-workitems”,然后选择“上传文件...”

    显示如何在 Visual Studio Code 本地模拟的 samples-workitems 容器中选择“上传文件”的屏幕截图。

  6. 选择要上传到本地模拟容器的文件。 此文件稍后由函数处理,以验证和调试函数代码。 文本文件可能最适合 Blob 触发器模板代码。

在本地运行函数

使用模拟存储中的文件,可以运行函数来模拟事件网格订阅引发的事件。 传递给触发器的事件信息取决于已添加到本地容器的文件。

  1. 设置任何断点并按 F5 启动项目进行本地调试。 Azure Functions Core Tools 应在终端窗口中运行。

  2. 返回 Azure 区域,展开“工作区”>“本地项目”>“Functions”,右键单击该函数,然后选择“立即执行函数...”

    显示如何在 Visual Studio Code 本地项目工作区的函数中选择“立即执行函数”按钮的屏幕截图。

  3. 在请求正文对话框中,键入 samples-workitems/<TEST_FILE_NAME>,将 <TEST_FILE_NAME> 替换为在本地存储模拟器中上传的文件的名称。

  4. 按 Enter 运行该函数。 提供的值是本地模拟器中 blob 的路径。 此字符串将传递到请求有效负载中的触发器,该触发器将在事件订阅调用函数来报告已将 blob 添加到容器时模拟有效负载。

  5. 查看此函数执行的输出。 将在输出中看到文件的名称及其记录的内容。 如果设置任何断点,则可能需要继续执行。

现在已在本地成功验证函数代码,是时候将项目发布到 Azure 中的新函数应用了。

准备 Azure 存储帐户

Azure 存储的事件订阅需要常规用途 v2 存储帐户。 可以使用适用于 Visual Studio Code 的 Azure 存储扩展来创建此存储帐户。

  1. 在 Visual Studio Code 中,再次按 F1 打开命令面板并输入 Azure Storage: Create Storage Account...。 系统提示时,提供以下信息:

    提示 操作
    输入新存储帐户的名称 提供全局唯一名称。 存储帐户名称的长度必须为 3 到 24 个字符,只能包含小写字母和数字。 为方便识别,我们将对资源组和函数应用使用相同的名称。
    选择新资源的位置 为了获得更好的性能,请选择你附近的区域

    该扩展会使用你提供的名称创建一个常规用途 v2 存储帐户。 同一名称也用于包含该存储帐户的资源组。 基于事件网格的 Blob 存储触发器需要常规用途 v2 存储帐户。

  2. 再次按 F1,在命令面板中输入 Azure Storage: Create Blob Container...。 系统提示时,提供以下信息:

    提示 操作
    选择资源 选择创建的常规用途 v2 存储帐户。
    输入新 blob 容器的名称 输入 samples-workitems,这是代码项目中引用的容器名称。

函数应用还需要一个存储帐户才能运行。 为了简化操作,本教程对 blob 触发器和函数应用使用同一存储帐户。 但是,在生产环境中,可能需要为函数应用使用单独的存储帐户。 有关详细信息,请参阅 Azure Functions 的存储注意事项

创建函数应用

使用以下步骤在 Flex 消耗计划中创建函数应用。 当应用托管在 Flex 消耗计划中时,Blob 存储触发器必须使用事件订阅。

  1. 在命令面板中,输入“Azure Functions: 在 Azure 中创建函数应用...(高级)”。

  2. 按提示操作并提供以下信息:

    Prompt 选择
    输入新的函数应用的全局唯一名称。 键入用于标识新函数应用的全局唯一名称,然后按 Enter。 函数应用名称的有效字符包括 a-z0-9-
    选择托管计划。 选择“Flex Consumption(预览版)”。
    选择一个运行时堆栈。 选择你一直在本地运行的语言堆栈和版本。
    选择新资源的资源组。 选择在其中创建了存储帐户的现有资源组。
    选择新资源的位置。 选择靠近你或靠近函数访问的其他服务的受支持区域中的位置。 不受支持的区域不显示。 有关详细信息,请参阅查看当前支持的区域
    选择一个存储帐户。 选择你创建的存储帐户的名称。
    为你的应用选择 Application Insights 资源。 选择“创建新的 Application Insights 资源”,然后根据提示提供用于存储函数运行时数据的实例的名称。

    创建函数应用后会显示一条通知。 在此通知中选择“查看输出”以查看创建结果,其中包括你创建的 Azure 资源。

部署函数代码

重要

部署到现有函数应用将始终覆盖该应用在 Azure 中的内容。

  1. 在命令面板中,输入并选择“Azure Functions: 部署到函数应用”。

  2. 选择你刚才创建的函数应用。 当系统提示覆盖以前的部署时,请选择“部署”,将函数代码部署到新的函数应用资源。

  3. 部署完成后,选择“查看输出”,以查看创建和部署结果,其中包括已创建的 Azure 资源。 如果错过了通知,请选择右下角的铃铛图标再次查看。

    “查看输出”窗口的屏幕截图。

更新应用程序设置

由于不会自动发布 local.settings.json 文件中所需的应用程序设置,因此必须将这些设置上传到函数应用,以便函数在 Azure 中正确运行。

  1. 在命令面板中,输入 Azure Functions: Download Remote Settings...,然后在“选择资源”提示中选择函数应用的名称

  2. 当系统提示 AzureWebJobsStorage 设置已存在时,请选择“是”以使用 Azure 中的实际存储帐户连接字符串覆盖本地模拟器设置

  3. local.settings.json 文件中,将本地模拟器设置替换为用于 AzureWebJobsStorage 的同一连接字符串。

  4. 删除 Flex 消耗计划中不支持的 FUNCTIONS_WORKER_RUNTIME 条目。

  5. 在命令面板中,输入 Azure Functions: Upload Local Settings...,然后在“选择资源”提示中选择函数应用的名称

现在,Functions 主机和触发器共享同一存储帐户。

生成终结点 URL

若要创建事件订阅,需要向事件网格提供特定终结点的 URL 来报告 Blob 存储事件。 此 blob 扩展 URL 由以下部分组成

组成部分 示例
基本函数应用 URL https://<FUNCTION_APP_NAME>.azurewebsites.net
特定于 Blob 的路径 /runtime/webhooks/blobs
函数查询字符串 ?functionName=Host.Functions.<FUNCTION_NAME>
Blob 扩展访问密钥 &code=<BLOB_EXTENSION_KEY>

Blob 扩展访问密钥旨在使其他人更难访问你的 blob 扩展终结点。 若要确定 Blob 扩展访问密钥,请执行以下操作:

  1. 在 Visual Studio Code 中,选择“活动”栏中的 Azure 图标。 在“资源”中,展开你的订阅,展开“函数应用”,右键单击你创建的函数应用,然后选择“在门户中打开”。

  2. 在左侧菜单中的“函数”下,选择“应用密钥”。

  3. 在“系统密钥”下,选择名为“blobs_extension”的密钥,并复制密钥值。

    需将此值包含在新终结点 URL 的查询字符串中。

  4. 根据以下示例,为 Blob 存储触发器创建新的终结点 URL:

    https://<FUNCTION_APP_NAME>.azurewebsites.net/runtime/webhooks/blobs?functionName=Host.Functions.EventGridBlobTrigger&code=<BLOB_EXTENSION_KEY>
    

    在此示例中,将 <FUNCTION_APP_NAME> 替换为你的函数应用的名称,并将 <BLOB_EXTENSION_KEY> 替换为你从门户获得的值。 如果为函数使用了其他名称,请将 EventGridBlobTrigger 替换为该函数名称。

现在可以使用此终结点 URL 创建事件订阅。

创建事件订阅

由 Azure 事件网格提供支持的事件订阅会根据订阅的 blob 容器中的更改引发事件。 然后,此事件将发送到函数的 blob 扩展终结点。 创建事件订阅后,将无法更新终结点 URL。

  1. 在 Visual Studio Code 中,选择“活动”栏中的 Azure 图标。 在“资源”中,展开订阅,然后展开“存储帐户”,右键单击之前创建的存储帐户,然后选择“在门户中打开”。

  2. 登录到 Azure 门户并记下存储帐户的资源组。 你将在同一组中创建其他资源,以便在完成后更轻松地清理资源。

  3. 从左侧菜单中选择“事件”选项。

    添加存储帐户事件

  4. 在“事件”窗口中,选择“+ 事件订阅”按钮,并将下表中的值提供到“基本信息”选项卡中:

    设置 建议值 说明
    Name myBlobEventSub 用于标识事件订阅的名称。 可以使用该名称快速查找事件订阅。
    事件架构 事件网格架构 对事件使用默认架构。
    系统主题名称 samples-workitems-blobs 表示容器的主题的名称。 该主题是随第一个订阅创建的,你将对未来的事件订阅使用该主题。
    筛选事件类型 已创建 Blob
    终结点类型 Webhook 该 Blob 存储触发器使用 Webhook 终结点。
    终结点 基于 Azure 的 URL 终结点 使用你生成的 URL 终结点,其中包括密钥值。
  5. 选择“确认选择”以验证终结点 URL。

  6. 选择“筛选器”选项卡,并向提示提供以下信息:

    设置 建议值 说明
    启用主题筛选 已启用 启用对哪些 Blob 可以触发函数的筛选。
    主题开头为 /blobServices/default/containers/<CONTAINER_NAME>/blobs/<BLOB_PREFIX> <CONTAINER_NAME<BLOB_PREFIX> 替换为你选择的值。 这会将订阅设置为仅针对以 BLOB_PREFIX 开头且位于 CONTAINER_NAME 容器中的 blob 触发。
    主题结尾为 .txt 确保函数仅由以 .txt 结尾的 blob 触发。

有关筛选到特定 blob 的详细信息,请参阅 Azure 事件中心的事件筛选

  1. 选择“创建”以创建事件订阅。

将文件上传到容器

可以使用 Visual Studio Code 将文件从计算机上传到 Blob 存储容器。

  1. 在 Visual Studio Code 中,按 F1 打开命令面板并键入 Azure Storage: Upload Files...

  2. 在“打开”对话框中,选择文件,最好是文本文件,然后选择“上传”

  3. 根据提示提供以下信息:

    设置 建议值 说明
    输入此上传的目标目录 默认值 只需接受默认值 /,即容器根目录。
    选择资源 存储帐户名称 选择在上一步中创建的存储帐户的名称。
    选择资源类型 Blob 容器 将会上传到 Blob 容器。
    选择 Blob 容器 samples-workitems 此值是上一步中创建的容器的名称。

浏览本地文件系统找到要上传的文件,然后选择“上传”按钮以上传文件

在 Azure 中验证函数

将文件上传到 samples-workitems 容器后,应触发函数。 可以通过在 Azure 门户中检查以下内容来验证:

  1. 在存储帐户中,转到“事件”页,选择“事件订阅”,应会看到已传递一个事件。 事件在图表上显示可能会有五分钟的延迟。

  2. 返回门户中的函数应用页,在“Functions”下找到函数并选“调用及其他”。 应会看到从成功的函数执行中写入的跟踪。

清理资源

若要继续执行下一步骤将 Azure 存储队列绑定添加到函数,需要保留到目前为止构建的所有资源。

否则,可以使用以下步骤删除函数应用及其相关资源,以免产生任何额外的费用。

  1. 在 Visual Studio Code 中,按 F1 打开命令面板。 在命令面板中,搜索并选择 Azure: Open in portal

  2. 选择你的函数应用,然后按 Enter。 随即将在 Azure 门户中打开函数应用页面。

  3. 在“概览”选项卡中,选择“资源组”旁边的命名链接。

    从函数应用页选择要删除的资源组的屏幕截图。

  4. 在“资源组”页上查看所包括的资源的列表,然后验证这些资源是否是要删除的。

  5. 选择“删除资源组”,然后按说明操作。

    可能需要数分钟才能删除完毕。 完成后会显示一个通知,持续数秒。 也可以选择页面顶部的钟形图标来查看通知。

有关 Functions 成本的详细信息,请参阅估算消耗计划成本

后续步骤