适用于 Azure Functions 的 Azure Blob 存储触发器

检测到新的或更新的 Blob 时,Blob 存储触发器会启动某个函数。 Blob 内容以函数输入的形式提供。

提示

根据存储容器中 blob 的更改,可通过多种方法执行函数代码。 如果选择使用 Blob 存储触发器,注意这里提供了两个实现:基于轮询的实现(即本文引用的实现)和基于事件的实现。 建议使用基于事件的实现,因为它的延迟比其他实现低。 此外,Flex 消耗计划仅支持基于事件的 Blob 存储触发器。

如需详细了解 Blob 存储触发器的两个实现之间的差异以及其他触发选项,请参阅使用 Blob

有关设置和配置详细信息,请参阅概述

重要

本文使用选项卡来支持多个版本的 Node.js 编程模型。 v4 模型目前处于预览状态,旨在为 JavaScript 和 TypeScript 开发人员提供更为灵活和直观的体验。 在升级指南中详细了解 v3 和 v4 之间的差异。

重要

本文使用选项卡来支持多个版本的 Python 编程模型。 v2 模型已正式发布,旨在提供一种更加以代码为中心的方法,用于通过修饰器创作函数。 有关 v2 模型工作原理的更多详细信息,请参阅 Azure Functions Python 开发人员指南

示例

可以使用以下 C# 模式之一创建 C# 函数:

  • 进程内类库:编译的 C# 函数,该函数在与 Functions 运行时相同的进程中运行。
  • 独立工作进程类库:编译的 C# 函数,该函数在独立于运行时的工作进程中运行。 需要独立的工作进程才能支持在非 LTS 版 .NET 和 .NET Framework 上运行的 C# 函数。
  • C# 脚本:主要在 Azure 门户中创建 C# 函数时使用。

以下示例是一个 C# 函数,该函数在独立工作进程中运行,并将 blob 触发器与 blob 输入和 blob 输出 blob 绑定配合使用。 在 test-samples-trigger 容器中创建 blob 时,会触发该函数。 它从 test-samples-input 容器读取文本文件,并基于已触发文件的名称在输出容器中创建一个新的文本文件。

    public static class BlobFunction
    {
        [Function(nameof(BlobFunction))]
        [BlobOutput("test-samples-output/{name}-output.txt")]
        public static string Run(
            [BlobTrigger("test-samples-trigger/{name}")] string myTriggerItem,
            [BlobInput("test-samples-input/sample1.txt")] string myBlob,
            FunctionContext context)
        {
            var logger = context.GetLogger("BlobFunction");
            logger.LogInformation("Triggered Item = {myTriggerItem}", myTriggerItem);
            logger.LogInformation("Input Item = {myBlob}", myBlob);

            // Blob Output
            return "blob-output content";
        }
    }

myblob 容器中添加或更新 Blob 时,该函数会写入一条日志。

@FunctionName("blobprocessor")
public void run(
  @BlobTrigger(name = "file",
               dataType = "binary",
               path = "myblob/{name}",
               connection = "MyStorageAccountAppSetting") byte[] content,
  @BindingName("name") String filename,
  final ExecutionContext context
) {
  context.getLogger().info("Name: " + filename + " Size: " + content.length + " bytes");
}

以下示例显示 blob 触发器 TypeScript 代码。 在 samples-workitems 容器中添加或更新 Blob 时,该函数会写入日志。

blob 触发器路径 samples-workitems/{name} 中的字符串 {name} 会创建一个绑定表达式,可以在函数代码中使用它来访问触发 blob 的文件名。 有关详细信息,请参阅本文下文中的 Blob 名称模式

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',
    handler: storageBlobTrigger1,
});

以下示例显示 blob 触发器 JavaScript 代码。 在 samples-workitems 容器中添加或更新 Blob 时,该函数会写入日志。

blob 触发器路径 samples-workitems/{name} 中的字符串 {name} 会创建一个绑定表达式,可以在函数代码中使用它来访问触发 blob 的文件名。 有关详细信息,请参阅本文下文中的 Blob 名称模式

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

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

下面的示例演示如何创建在将文件添加到 source blob 存储容器时运行的函数。

函数配置文件 (function.json) 包含一个绑定,其 typeblobTriggerdirection 设置为 in

{
  "bindings": [
    {
      "name": "InputBlob",
      "type": "blobTrigger",
      "direction": "in",
      "path": "source/{name}",
      "connection": "MyStorageAccountConnectionString"
    }
  ]
}

下面是 run.ps1 文件的关联代码。

param([byte[]] $InputBlob, $TriggerMetadata)

Write-Host "PowerShell Blob trigger: Name: $($TriggerMetadata.Name) Size: $($InputBlob.Length) bytes"

此示例使用 SDK 类型直接访问 Blob 存储触发器提供的基础 BlobClient 对象:

import logging

import azure.functions as func
import azurefunctions.extensions.bindings.blob as blob

app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)
@app.blob_trigger(
    arg_name="client", path="PATH/TO/BLOB", connection="AzureWebJobsStorage"
)
def blob_trigger(client: blob.BlobClient):
    logging.info(
        f"Python blob trigger function processed blob \n"
        f"Properties: {client.get_blob_properties()}\n"
        f"Blob content head: {client.download_blob().read(size=1)}"
    )

有关使用其他 SDK 类型的示例,请参阅 ContainerClientStorageStreamDownloader 示例。

若要了解详细信息,包括如何在项目中启用 SDK 类型绑定,请参阅 SDK 类型绑定

此示例记录传入 Blob 元数据中的信息。

import logging
import azure.functions as func

app = func.FunctionApp()

@app.function_name(name="BlobTrigger1")
@app.blob_trigger(arg_name="myblob", 
                  path="PATH/TO/BLOB",
                  connection="CONNECTION_SETTING")
def test_function(myblob: func.InputStream):
   logging.info(f"Python blob trigger function processed blob \n"
                f"Name: {myblob.name}\n"
                f"Blob Size: {myblob.length} bytes")

特性

进程内独立工作进程 C# 库都使用 BlobAttribute 特性来定义函数。 C# 脚本改用 function.json 配置文件,如 C# 脚本指南中所述。

该特性的构造函数采用以下参数:

参数 说明
BlobPath Blob 的路径。
Connection 指定如何连接到 Azure Blob 的应用设置或设置集合的名称。 请参阅连接
访问 表示是要读取还是写入。
Source 设置触发事件的源。 将 BlobTriggerSource.EventGrid 用于基于事件网格的 Blob 触发器,这样可以显著缩短延迟。 默认值为 BlobTriggerSource.LogsAndContainerScan,它使用标准轮询机制来检测容器中的更改。

下面是某个方法签名中的 BlobTrigger 特性:

        [Function(nameof(BlobFunction))]
        [BlobOutput("test-samples-output/{name}-output.txt")]
        public static string Run(
            [BlobTrigger("test-samples-trigger/{name}")] string myTriggerItem,
            [BlobInput("test-samples-input/sample1.txt")] string myBlob,
            FunctionContext context)

在本地开发时,需要将应用程序设置添加到 Values 集合中的 local.settings.json 文件中。

修饰符

仅适用于 Python v2 编程模型。

对于使用修饰器定义的 Python v2 函数,blob_trigger 修饰器上的以下属性可定义 Blob 存储触发器:

properties 说明
arg_name 在函数签名中声明参数名称。 触发函数时,此参数的值包含队列消息的内容。
path 要监视的容器。 可以是某种 Blob 名称模式
connection 存储帐户连接字符串。
source 设置触发事件的源。 将 EventGrid 用于基于事件网格的 Blob 触发器,这样可以显著缩短延迟。 默认值为 LogsAndContainerScan,该机制使用标准轮询机制检测容器中的更改。

对于使用 function.json 定义的 Python 函数,请参阅“配置”部分。

批注

@BlobTrigger 特性用于授予对触发函数的 blob 的访问权限。 有关详细信息,请参阅触发器示例。 使用 source 属性设置触发事件的源。 将 EventGrid 用于基于事件网格的 Blob 触发器,这样可以显著缩短延迟。 默认值为 LogsAndContainerScan,该机制使用标准轮询机制检测容器中的更改。 |

配置

仅适用于 Python v1 编程模型

下表说明了可以在传递给 app.storageBlob() 方法的 options 对象上设置的属性。

properties 说明
路径 要监视的容器。 可以是某种 Blob 名称模式
连接 指定如何连接到 Azure Blob 的应用设置或设置集合的名称。 请参阅连接
设置触发事件的源。 将 EventGrid 用于基于事件网格的 Blob 触发器,这样可以显著缩短延迟。 默认值为 LogsAndContainerScan,该机制使用标准轮询机制检测容器中的更改。

下表解释了在 function.json 文件中设置的绑定配置属性。

“function.json”属性 说明
type 必须设置为 blobTrigger。 在 Azure 门户中创建触发器时,会自动设置此属性。
direction 必须设置为 in。 在 Azure 门户中创建触发器时,会自动设置此属性。 用法部分中已阐述异常。
name 表示函数代码中的 Blob 的变量的名称。
路径 要监视的容器。 可以是某种 Blob 名称模式
连接 指定如何连接到 Azure Blob 的应用设置或设置集合的名称。 请参阅连接
设置触发事件的源。 将 EventGrid 用于基于事件网格的 Blob 触发器,这样可以显著缩短延迟。 默认值为 LogsAndContainerScan,该机制使用标准轮询机制检测容器中的更改。

有关完整示例的信息,请参阅示例部分

Metadata

Blob 触发器提供了几个元数据属性。 这些属性可在其他绑定中用作绑定表达式的一部分,或者用作代码中的参数。 这些值具有与 CloudBlob 类型相同的语义。

属性 类型​​ 说明
BlobTrigger string 触发 Blob 的路径。
Uri System.Uri 主位置的 blob 的 URI。
Properties BlobProperties Blob 的系统属性。
Metadata IDictionary<string,string> Blob 的用户定义元数据。

以下示例记录了触发 blob 的路径,包括容器:

public static void Run(string myBlob, string blobTrigger, ILogger log)
{
    log.LogInformation($"Full blob path: {blobTrigger}");
} 

Metadata

Blob 触发器提供了几个元数据属性。 这些属性可在其他绑定中用作绑定表达式的一部分,或者用作代码中的参数。

属性 说明
blobTrigger 触发 Blob 的路径。
uri 主位置的 blob 的 URI。
properties Blob 的系统属性。
metadata Blob 的用户定义元数据。

可以从提供的 context 对象的 triggerMetadata 属性中获取元数据,如下面的示例所示,该属性记录触发 blob 的路径 (blobTrigger),包括容器:

context.log(`Full blob path: ${context.triggerMetadata.blobTrigger}`);

Metadata

可以通过 $TriggerMetadata 参数获取元数据。

使用情况

Blob 触发器支持的绑定类型取决于函数应用中使用的扩展包版本和 C# 形式。

Blob 触发器可以绑定到以下类型:

类型 说明
string Blob 内容即字符串。 在 blob 内容为简单文本时使用。
byte[] Blob 内容的字节数。
JSON 可序列化类型 当 blob 包含 JSON 数据时,Functions 会尝试将 JSON 数据反序列化为普通的旧 CLR 对象 (POCO) 类型。
(预览版1
Blob 内容的输入流。
BlobClient
BlockBlobClient
PageBlobClient
AppendBlobClient
BlobBaseClient
(预览版1
连接到 blob 的客户端。 这提供了对 blob 处理的充分控制,如果连接具有足够的权限,则可用于写回 blob。

1 若要使用这些类型,需要引用 Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs 5.1.1-preview2 或更高版本以及 SDK 类型绑定的常见依赖项

仅当 blob 大小较小时才建议绑定到 stringByte[]。 我们推荐此做法,因为整个 blob 内容都会加载到内存中。 对于大多数 blob,请使用 StreamBlobClient 类型。 有关详细信息,请参阅并发和内存使用情况

如果尝试绑定到某个存储 SDK 类型时收到了错误消息,请确保已引用正确的存储 SDK 版本

还可使用 StorageAccountAttribute 指定要使用的存储帐户。 如果需要使用一个不同于库中的其他函数的存储帐户,可以执行此操作。 构造函数采用包含存储连接字符串的应用设置的名称。 可以在参数、方法或类级别应用该特性。 以下示例演示类级别和方法级别:

[StorageAccount("ClassLevelStorageAppSetting")]
public static class AzureFunctions
{
    [FunctionName("BlobTrigger")]
    [StorageAccount("FunctionLevelStorageAppSetting")]
    public static void Run( //...
{
    ....
}

要使用的存储帐户按以下顺序确定:

  • BlobTrigger 特性的 Connection 属性。
  • 作为 BlobTrigger 特性应用到同一参数的 StorageAccount 特性。
  • 应用到函数的 StorageAccount 特性。
  • 应用到类的 StorageAccount 特性。
  • 函数应用的默认存储帐户,在 AzureWebJobsStorage 应用程序设置中定义。

@BlobTrigger 特性用于授予对触发函数的 blob 的访问权限。 有关详细信息,请参阅触发器示例

将 blob 数据作为函数的第一个参数访问。

通过与 function.json 文件中绑定名称参数指定的名称匹配的字符串参数访问 Blob 数据。

通过类型为 InputStream 的参数访问 blob 数据。 有关详细信息,请参阅触发器示例

Functions 还支持用于 Azure Blob 存储的 Python SDK 类型绑定,这样便可以使用以下基础 SDK 类型处理 Blob 数据:

重要

对 Python 的 SDK 类型支持目前为预览版,并且仅支持 Python v2 编程模型。 有关详细信息,请参阅 Python 中的 SDK 类型

连接

connection 属性是对环境配置的引用,它指定应用应如何连接到 Azure Blob。 它可能指定:

如果配置的值既是单个设置的完全匹配,也是其他设置的前缀匹配,则使用完全匹配。

连接字符串

要获取连接字符串,请执行管理存储帐户访问密钥中显示的步骤。 连接字符串必须属于某个常规用途存储帐户,而不能属于Blob 存储帐户

此连接字符串应存储在应用程序设置中,其名称与绑定配置的 connection 属性指定的值匹配。

如果应用设置名称以“AzureWebJobs”开始,则只能在此处指定该名称的余下部分。 例如,如果将 connection 设置为“MyStorage”,则 Functions 运行时会查找名为“AzureWebJobsMyStorage”的应用设置。 如果将 connection 留空,函数运行时将使用名为 AzureWebJobsStorage 的应用设置中的默认存储连接字符串。

基于标识的连接

如果使用 5.x 或更高版本的扩展,则无需将连接字符串与机密配合使用,可以让应用使用 Azure Active Directory 标识。 要使用标识,需要定义公共前缀下的设置,该前缀映射到触发器和绑定配置中的 connection 属性。

如果将 connection 设置为“AzureWebJobsStorage”,请参阅使用标识连接到主机存储。 对于所有其他连接,扩展需要以下属性:

属性 环境变量模板 说明 示例值
Blob 服务 URI <CONNECTION_NAME_PREFIX>__serviceUri1 要连接到的 Blob 服务的数据平面 URI,使用 HTTPS 方案。 https://<storage_account_name>.blob.core.chinacloudapi.cn

1 <CONNECTION_NAME_PREFIX>__blobServiceUri 可以用作别名。 如果连接配置将由 Blob 触发器使用,则 blobServiceUri 还必须带有 queueServiceUri。 请参阅下文。

如果要跨 Blob、队列和/或表使用总体连接配置,则无法使用 serviceUri 窗体。 URI 只能指定 Blob 服务。 作为一种替代方案,可以为每个服务专门提供一个 URI,从而允许使用单个连接。 如果这两个版本均提供,则将使用多服务窗体。 若要为多个服务(而不是 <CONNECTION_NAME_PREFIX>__serviceUri)配置连接,请设置:

属性 环境变量模板 说明 示例值
Blob 服务 URI <CONNECTION_NAME_PREFIX>__blobServiceUri 要连接到的 Blob 服务的数据平面 URI,使用 HTTPS 方案。 https://<storage_account_name>.blob.core.chinacloudapi.cn
队列服务 URI(Blob 触发器需要2 <CONNECTION_NAME_PREFIX>__queueServiceUri 使用 HTTPS 方案的队列服务的数据平面 URI。 仅 Blob 触发器需要该值。 https://<storage_account_name>.queue.core.chinacloudapi.cn

2 Blob 触发器通过将有害 blob 写入队列来处理多次重试中出现的故障。 在 serviceUri 窗体中,将使用 AzureWebJobsStorage 连接。 但是,在指定 blobServiceUri 时,还必须为 queueServiceUri 提供队列服务 URI。 建议使用与 Blob 服务相同的存储帐户中的服务。 还需要通过分配存储队列数据参与者等角色来确保触发器可以在配置的队列服务中读取和写入消息。

可以设置其他属性来自定义连接。 请参阅基于标识的连接的通用属性

在 Azure Functions 服务中托管时,基于标识的连接将使用托管标识。 默认情况下使用系统分配的标识,但可以使用 credentialclientID 属性来指定用户分配的标识。 请注意,不支持为用户分配的标识配置资源 ID。 在其他上下文(如本地开发)中运行时,将改用开发人员标识,尽管可以进行自定义。 请参阅使用基于标识的连接进行本地开发

向标识授予权限

无论使用何种标识,都必须具有执行所需操作的权限。 对于大多数 Azure 服务,这意味着你需要使用内置角色或者提供这些权限的自定义角色在 Azure RBAC 中分配角色

重要

某些权限可能由并非所有上下文都需要的目标服务公开。 尽可能遵循最低权限原则,仅授予标识所需的权限。 例如,如果应用只需要从数据源进行读取即可,则使用仅具有读取权限的角色。 分配一个也具有该服务写入权限的角色并不恰当,因为对于读取操作来说,写入是多余的权限。 同样,你也希望确保角色分配的范围仅限于需要读取的资源。

你需要创建一个角色分配,以在运行时提供对 Blob 容器的访问权限。 所有者等管理角色还不够。 下表显示了在正常操作中使用 Blob 存储扩展时建议使用的内置角色。 根据所编写的代码,应用程序可能需要进一步的权限。

绑定类型 内置角色示例
触发器 存储 Blob 数据所有者存储队列数据参与者1

此外,还必须向 AzureWebJobsStorage 连接授予额外的权限。2
输入绑定 存储 Blob 数据读者
输出绑定 存储 Blob 数据所有者

1 Blob 触发器通过将有害 blob 写入到连接所指定的存储帐户上的队列来处理多次重试中出现的故障。

2 AzureWebJobsStorage 连接在内部用于启用触发器的 blob 和队列。 如果将其配置为使用基于标识的连接,则该连接将需要超出默认要求的其他权限。 存储 Blob 数据所有者存储队列数据参与者存储帐户参与者角色涵盖了所需的权限。 若要了解更多信息,请参阅使用标识连接到主机存储

Blob 名称模式

可以在 function.jsonpath 属性中或者在 BlobTrigger 特性构造函数中指定 Blob 名称模式。 名称模式可以是筛选器或绑定表达式。 以下部分提供了有关示例。

提示

容器名称不能在名称模式中包含解析程序。

获取文件名和扩展名

以下示例演示如何分别绑定到 Blob 文件名和扩展名:

"path": "input/{blobname}.{blobextension}",

如果 Blob 名为 original-Blob1.txt,则函数代码中 blobnameblobextension 变量的值为 original-Blob1txt

按 Blob 名称筛选

以下示例仅根据 input 容器中以字符串“original-”开头的 Blob 触发:

"path": "input/original-{name}",

如果 Blob 名称为 original-Blob1.txt,则函数代码中 name 变量的值为 Blob1.txt

按文件类型筛选

以下示例仅根据 .png 文件触发:

"path": "samples/{name}.png",

按文件名中的大括号筛选

若要查找文件名中的大括号,请使用两个大括号将大括号转义。 以下示例筛选名称中包含大括号的 Blob:

"path": "images/{{20140101}}-{name}",

如果 Blob 名为 {20140101}-soundfile.mp3,则函数代码中的 name 变量值为 soundfile.mp3

轮询和延迟

轮询在检查日志和运行定期容器扫描之间起到混合作用。 每次以 10,000 个为一组扫描 Blob,并在间隔之间使用继续标记。 如果函数应用基于消耗计划,则当函数应用处于空闲状态时,处理新 Blob 会出现长达 10 分钟的延迟。

警告

存储日志将基于“尽力而为”的准则创建。 不保证捕获所有事件。 在某些情况下可能会遗漏某些日志。

如果需要更快或更可靠的 blob 处理,应考虑切换托管以使用启用了 Always On 的应用服务计划,这可能会导致成本增加。 还可考虑使用经典轮询 blob 触发器以外的触发器。 有关详细信息及 blob 存储容器的各种触发选项的比较,请参阅 blob 容器上的触发器

Blob 回执

Azure Functions 运行时确保没有为相同的新 blob 或更新 blob 多次调用 blob 触发器函数。 为了确定是否已处理给定的 blob 版本,它会维护 blob 回执

Azure Functions 将 Blob 回执存储在函数应用的 Azure 存储帐户中名为 azure-webjobs-hosts 的容器中(由 AzureWebJobsStorage 应用设置定义)。 Blob 回执包含以下信息:

  • 触发的函数(<FUNCTION_APP_NAME>.Functions.<FUNCTION_NAME>,例如:MyFunctionApp.Functions.CopyBlob
  • 容器名称
  • Blob 类型(BlockBlobPageBlob
  • Blob 名称
  • ETag(blob 版本标识符,例如:0x8D1DC6E70A277EF

若要强制重新处理某个 blob,可从 azure-webjobs-hosts 容器中手动删除该 blob 的 blob 回执。 虽然重新处理可能不会立即发生,但它肯定会在稍后的时间点发生。 若要立即重新处理,可以更新 azure-webjobs-hosts/blobscaninfo 中的 scaninfo Blob 。 将再次扫描 LatestScan 属性后具有上次修改时间戳的任何 Blob。

有害 Blob

当给定 blob 的 blob 触发函数失败时,Azure Functions 将默认重试该函数共计 5 次。

如果 5 次尝试全部失败,Azure Functions 会将消息添加到名为 webjobs-blobtrigger-poison 的存储队列。 最大尝试次数可配置。 使用相同的 MaxDequeueCount 设置处理有害 Blob 和有害队列消息。 有害 Blob 的队列消息是包含以下属性的 JSON 对象:

  • FunctionId(格式为 <FUNCTION_APP_NAME>.Functions.<FUNCTION_NAME>
  • BlobType(BlockBlobPageBlob
  • ContainerName
  • BlobName
  • ETag(blob 版本标识符,例如:0x8D1DC6E70A277EF

内存使用率和并发性

绑定到不支持流式处理的输出类型(例如 stringByte[])时,运行时必须在处理期间将整个 Blob 多次加载到内存中。 这可能会导致处理 Blob 时内存使用率高于预期。 如果可能,请使用支持流的类型。 类型支持取决于 C# 模式和扩展版本。 有关详细信息,请参阅绑定类型

此时,运行时必须在处理期间将整个 Blob 多次加载到内存中。 这可能会导致处理 Blob 时内存使用率高于预期。

当多个函数实例同时处理 Blob 数据时,内存使用率可能会进一步受到影响。 如果使用 Blob 触发器遇到内存问题,请考虑减少允许的并发执行数。 当然,减少并发可能会产生增加等待处理的 blob 积压的副作用。 函数应用的内存限制取决于计划。 有关详细信息,请参阅服务限制

可以控制并发执行数的方式取决于所使用的存储扩展的版本。

使用存储扩展版本 5.0.0 或更高版本时,可以使用 host.json 的 blob 配置中的 maxDegreeOfParallelism 设置来控制触发并发。

限制分别应用于使用 blob 触发器的每个函数。

host.json 属性

host.json 文件包含控制 blob 触发器行为的设置。 有关可用设置的详细信息,请参阅 host.json 设置部分。

后续步骤