快速入门:使用 Azure Functions 响应 Azure Cosmos DB 中的数据库更改

在本快速入门中,你将使用 Visual Studio Code 生成一个应用,以响应 Azure Cosmos DB 中 No SQL 数据库中的数据库更改。

项目源使用Azure开发人员 CLI (azd) 扩展和Visual Studio Code来简化本地初始化和验证项目代码,以及将代码部署到Azure。 此部署遵循安全且可缩放的 Azure Functions 部署的当前最佳做法。

虽然消耗计划遵循 pay-for-you-use 计费模型,但此代码项目会创建其他Azure资源,包括Azure Cosmos DB实例。 请确保在使用完毕后清理资源,以避免持续产生费用。

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

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

先决条件

  • Node.js 18.x 或更高版本。 可以使用 node --version 命令检查你的版本。

初始化项目

使用Azure开发人员 CLI(azd)从模板创建本地Azure Functions代码项目。

  1. 从终端运行以下命令 azd init ,从模板创建本地项目:

    azd init --template functions-quickstart-dotnet-azd-cosmosdb -e cosmosdbchanges-dotnet
    

    此命令从 template 存储库中拉取项目文件并在新文件夹中初始化项目。 在 azd 中,环境用于维护应用的唯一部署上下文,你可以定义多个环境。 它也是在 Azure 中创建的资源组的名称的一部分。

  2. 更改为项目目录:

    cd functions-quickstart-dotnet-azd-cosmosdb
    
  1. 从终端运行以下命令 azd init ,从模板创建本地项目:

    azd init --template functions-quickstart-java-azd-cosmosdb -e cosmosdbchanges-java
    

    此命令从 template 存储库中拉取项目文件并在新文件夹中初始化项目。 在 azd 中,环境用于维护应用的唯一部署上下文,你可以定义多个环境。 它也是在 Azure 中创建的资源组的名称的一部分。

  2. 更改为项目目录:

    cd functions-quickstart-java-azd-cosmosdb
    
  1. 从终端运行以下命令 azd init ,从模板创建本地项目:

    azd init --template functions-quickstart-javascript-azd-cosmosdb -e cosmosdbchanges-js
    

    此命令从 template 存储库中拉取项目文件并在新文件夹中初始化项目。 在 azd 中,环境用于维护应用的唯一部署上下文,你可以定义多个环境。 它也是在 Azure 中创建的资源组的名称的一部分。

  2. 更改为项目目录:

    cd functions-quickstart-javascript-azd-cosmosdb
    
  1. 从终端运行以下命令 azd init ,从模板创建本地项目:

    azd init --template functions-quickstart-powershell-azd-cosmosdb -e cosmosdbchanges-ps
    

    此命令从 template 存储库中拉取项目文件并在新文件夹中初始化项目。 在 azd 中,环境用于维护应用的唯一部署上下文,你可以定义多个环境。 它也是在 Azure 中创建的资源组的名称的一部分。

  2. 更改为项目目录:

    cd functions-quickstart-powershell-azd-cosmosdb
    
  1. 从终端运行以下命令 azd init ,从模板创建本地项目:

    azd init --template functions-quickstart-typescript-azd-cosmosdb -e cosmosdbchanges-ts
    

    此命令从 template 存储库中拉取项目文件并在新文件夹中初始化项目。 在 azd 中,环境用于维护应用的唯一部署上下文,你可以定义多个环境。 它也是在 Azure 中创建的资源组的名称的一部分。

  2. 更改为项目目录:

    cd functions-quickstart-typescript-azd-cosmosdb
    
  1. 从终端运行以下命令 azd init ,从模板创建本地项目:

    azd init --template functions-quickstart-python-azd-cosmosdb -e cosmosdbchanges-py
    

    此命令从 template 存储库中拉取项目文件并在新文件夹中初始化项目。 在 azd 中,环境用于维护应用的唯一部署上下文,你可以定义多个环境。 它也是在 Azure 中创建的资源组的名称的一部分。

  2. 更改为项目目录:

    cd functions-quickstart-python-azd-cosmosdb
    
  1. 根据本地作系统运行此命令,授予配置脚本所需的权限:

    使用足够的权限运行此命令:

    chmod +x ./infra/scripts/*.sh
    
  2. 在 Visual Studio Code 中打开项目:

    code .
    

必须先在 Azure 中创建资源,然后才能在本地运行应用。 此项目不使用 Azure Cosmos DB 的本地仿真。

创建 Azure 资源

此项目配置为使用 azd provision 命令在消耗计划中创建函数应用,以及创建符合当前最佳实践的其他必需的 Azure 资源。

  1. 在 Visual Studio Code 中,按 F1 打开命令面板,搜索并运行命令 Azure Developer CLI (azd): Sign In with Azure Developer CLI,然后使用 Azure 帐户登录。

  2. 按 F1 打开命令面板,搜索并运行命令 Azure Developer CLI (azd): Provision Azure resources (provision) 以创建所需的 Azure 资源:

  3. 在终端窗口中出现提示时,请提供以下所需的部署参数:

    Prompt Description
    选择要使用的 Azure 订阅 选择您希望创建资源的订阅。
    位置 部署参数 要在其中创建包含新 Azure 资源的资源组的 Azure 区域。 仅显示当前支持消耗计划的区域。
    vnetEnabled 部署参数 虽然模板支持在虚拟网络中创建资源,但为了简化部署和测试,请选择 False。

    该 azd provision 命令使用 Bicep 配置文件对这些提示的响应来创建和配置这些所需的 Azure 资源,遵循最新的最佳做法:

    • Azure Cosmos DB 帐户
    • Azure 存储(必需)和 应用程序洞察(推荐)
    • 帐户的访问策略和角色
    • 使用托管标识(而不是存储的连接字符串)的服务间连接

    预配后挂钩还会在本地运行时生成所需的 local.settings.json 文件。 此文件还包含连接到 Azure 中的 Azure Cosmos DB 数据库所需的设置。

    小窍门

    如果预配过程中的任何步骤都失败,可以在解决任何问题后再次重新运行 azd provision 该命令。

    命令成功完成后,可以在本地运行项目代码并在 Azure 中的 Azure Cosmos DB 数据库上触发。

在本地运行函数

Visual Studio Code 与 Azure Functions Core 工具 集成,可在发布到 Azure 中的新函数应用之前在本地开发计算机上运行此项目。

  1. 按 F1 并在命令面板中搜索并运行命令 Azurite: Start。

  2. 若要在本地启动函数,请按 F5 或左侧活动栏中的 “运行和调试 ”图标。 “终端”面板将显示 Core Tools 的输出。 应用在 终端 面板中启动,可以看到在本地运行的函数的名称。

    如果在 Windows 上运行时遇到问题,请确保用于 Visual Studio Code 的默认终端未设置为“WSL Bash”。

  3. 如果 Core Tools 仍在 终端中运行,请按 F1 并在命令面板中搜索并运行命令 NoSQL: Create Item... ,并选择 document-db 数据库和 documents 容器。

  4. 将 新 Item.json 文件的内容替换为此 JSON 数据,然后选择“ 保存:

    {
        "id": "doc1",
        "title": "Sample document",
        "content": "This is a sample document for testing my Azure Cosmos DB trigger in Azure Functions."
    }
    

    选择 “保存”后,你将在终端中看到函数的执行,本地文档将更新为包含服务添加的元数据。

  5. 完成后,在终端窗口中按 Ctrl+C 停止 func.exe 主机进程。

查看代码(可选)

该函数基于 Azure Cosmos DB NoSQL 数据库中的更改源触发。

这些环境变量配置触发器如何监视更改源:

  • COSMOS_CONNECTION__accountEndpoint:Cosmos DB 帐户终结点
  • COSMOS_DATABASE_NAME:要监视的数据库的名称
  • COSMOS_CONTAINER_NAME:要监视的容器的名称

这些环境变量会在azd provision操作过程中,在 Azure(函数应用设置)和本地(local.settings.json)中为您创建。

环境变量 COSMOS_CONNECTION 配置触发器使用的 Cosmos DB 帐户终结点。 在 azd provision 操作期间,会在Azure(函数应用设置)和本地(local.settings.json)中创建此环境变量。 数据库和容器名称在触发器配置中定义。

可以查看定义Azure Cosmos DB触发器的代码:

using System;
using System.Collections.Generic;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace Company.Function
{
    public class CosmosTrigger
    {
        private readonly ILogger _logger;

        public CosmosTrigger(ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger<CosmosTrigger>();
        }

        [Function("cosmos_trigger")]
        public void Run([CosmosDBTrigger(
            databaseName: "%COSMOS_DATABASE_NAME%",
            containerName: "%COSMOS_CONTAINER_NAME%",
            Connection = "COSMOS_CONNECTION",
            LeaseContainerName = "leases",
            CreateLeaseContainerIfNotExists = true)] IReadOnlyList<MyDocument> input)
        {
            if (input != null && input.Count > 0)
            {
                _logger.LogInformation("Documents modified: " + input.Count);
                _logger.LogInformation("First document Id: " + input[0].id);
            }
        }
    }
    public class MyDocument
    {
        /// <summary>
        /// The unique identifier for the document.
        /// </summary>
        public required string id { get; set; }

        /// <summary>
        /// A text field in the document.
        /// </summary>
        public required string Text { get; set; }

        /// <summary>
        /// A numeric field in the document.
        /// </summary>
        public int Number { get; set; }

        /// <summary>
        /// A boolean field in the document.
        /// </summary>
        public bool Boolean { get; set; }
    }
}

可在此处查看完整的模板项目。

package com.function;

import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.annotation.CosmosDBTrigger;
import com.microsoft.azure.functions.annotation.FunctionName;

public class CosmosTrigger {

    @FunctionName("cosmos_trigger")
    public void run(
        @CosmosDBTrigger(
            name = "input",
            databaseName = "%COSMOS_DATABASE_NAME%",
            containerName = "%COSMOS_CONTAINER_NAME%",
            connection = "COSMOS_CONNECTION",
            leaseContainerName = "leases",
            createLeaseContainerIfNotExists = true
        ) Object[] items,
        final ExecutionContext context
    ) {
        if (items != null && items.length > 0) {
            context.getLogger().info("Documents modified: " + items.length);
            context.getLogger().info("First document Id: " + items[0].toString());
        }
    }
}

可在此处查看完整的模板项目。

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

app.cosmosDB('cosmos_trigger', {
    connection: 'COSMOS_CONNECTION',
    databaseName: '%COSMOS_DATABASE_NAME%',
    containerName: '%COSMOS_CONTAINER_NAME%',
    leaseContainerName: 'leases',
    createLeaseContainerIfNotExists: true,
    handler: (documents, context) => {
        if (documents && documents.length > 0) {
            context.log(`Documents modified: ${documents.length}`);
            context.log(`First document Id: ${documents[0].id}`);
        }
    }
});

可在此处查看完整的模板项目。

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

export async function cosmos_trigger(documents: unknown[], context: InvocationContext): Promise<void> {
    context.log(`Cosmos DB function processed ${documents.length} documents`);

    if (documents && documents.length > 0) {
        for (const doc of documents) {
            context.log(`First document: ${JSON.stringify(doc)}`);
            if (doc && typeof doc === "object" && "id" in doc) {
                context.log(`First document id: ${(doc as { id?: string }).id}`);
            }
        }
    } else {
        context.log("No documents found.");
    }
}


app.cosmosDB('cosmos_trigger', {
    connection: 'COSMOS_CONNECTION',
    databaseName: 'documents-db',
    containerName: 'documents',
    createLeaseContainerIfNotExists: true,
    handler: cosmos_trigger
});

可在此处查看完整的模板项目。

此 function.json 文件中定义了触发器:

{
  "bindings": [
    {
      "type": "cosmosDBTrigger",
      "name": "InputDocuments",
      "direction": "in",
      "databaseName": "%COSMOS_DATABASE_NAME%",
      "containerName": "%COSMOS_CONTAINER_NAME%",
      "connection": "COSMOS_CONNECTION",
      "leaseContainerName": "leases",
      "createLeaseContainerIfNotExists": true
    }
  ]
}

以下代码在触发器执行时运行:

param($InputDocuments, $TriggerMetadata)

if ($InputDocuments -and $InputDocuments.Count -gt 0) {
    Write-Host "Documents modified: $($InputDocuments.Count)"
    Write-Host "First document Id: $($InputDocuments[0].id)"
}

可在此处查看完整的模板项目。

import os
import azure.functions as func
import logging

app = func.FunctionApp()


@app.cosmos_db_trigger(
    arg_name="documents",
    container_name=os.environ.get("COSMOS_CONTAINER_NAME"),
    database_name=os.environ.get("COSMOS_DATABASE_NAME"),
    connection="COSMOS_CONNECTION",
    create_lease_container_if_not_exists="true",
)
def cosmos_trigger(documents: func.DocumentList):
    logging.info("Python CosmosDB triggered.")
    logging.info(f"Documents modified: {len(documents)}")
    if documents:
        for doc in documents:
            logging.info(f"First document: {doc.to_json()}")
            logging.info(f"First document id: {doc.get('id')}")
    else:
        logging.info("No documents found.")

可在此处查看完整的模板项目。

在本地查看并验证函数代码后,即可将项目发布到 Azure。

部署到 Azure 云

可以从 Visual Studio Code 运行 azd deploy 命令,将项目代码部署到 Azure 中已预配的资源。

  1. 按 F1 打开命令面板。

  2. 搜索并运行命令 Azure Developer CLI (azd): Deploy to Azure (deploy)。

    命令 azd deploy 将代码打包并部署到部署容器。 然后,应用将启动并在已部署的包中运行。

    命令成功完成后,应用在 Azure 中运行。

在 Azure 上调用函数

  1. 在 Visual Studio Code 中,按 F1 并在命令面板中搜索并运行命令 Azure: Open in portal,选择 Function app并选择新应用。 如有必要,请使用 Azure 帐户登录。

    此命令将在 Azure 门户中打开新的函数应用。

  2. 在主页的“ 概述 ”选项卡中,选择函数应用名称,然后选择“ 日志 ”选项卡。

  3. 在 Visual Studio Code 中使用 NoSQL: Create Item 命令,再次将文档添加到容器中,如前所述。

  4. 再次验证函数是否由受监视容器中的更新触发。

重新部署代码

可以根据需要多次运行 azd deploy 命令,以便将代码更新部署到函数应用。

注释

已部署的代码文件始终被最新的部署包覆盖。

对 azd 提示的初始响应和 azd 生成的任何环境变量都本地存储在你的命名环境中。 使用 azd env get-values 命令查看创建 Azure 资源时使用的环境中的所有变量。

清理资源

使用完函数应用和相关资源后,可以使用此命令从 Azure 中删除函数应用及其相关资源,并避免产生任何进一步的成本:

azd down --no-prompt

注释

--no-prompt 选项指示 azd 在未经你确认的情况下删除资源组。

此命令不会影响本地代码项目。