快速入门:使用 Durable Functions 生成无服务器工作流

在本快速入门中,你将使用 Azure 开发人员命令行工具生成一个无服务器工作流,用于协调并行运行的多个任务。 在本地测试代码后,将其部署到 Azure Functions 中弹性消耗计划中运行的新无服务器函数应用。

该项目使用 Azure 开发人员 CLI(azd)简化将代码部署到 Azure。 此部署遵循安全且可缩放的 Azure Functions 部署的当前最佳做法。 本快速入门演示 Durable Functions 中的扇出/扇入模式,这是一个扩展,用于协调持久执行的有状态工作流。 该示例并行获取文章标题——调度策略展开为多个并行活动,然后收拢以汇总结果。

默认情况下,Flex Consumption 计划遵循按需付费的计费模型,这意味着使用此计划完成本快速入门会在您的 Azure 帐户中产生少量费用,约为几美元美分或更少。

重要

此语言的示例项目当前不可用。 请稍后检查或改为切换到以下语言之一:C#、Python 或 TypeScript。

初始化项目

azd init使用命令从模板创建本地 Durable Functions 代码项目。

  1. 在本地终端或命令提示符下,在空文件夹中运行此 azd init 命令:

    azd init --template durable-functions-quickstart-dotnet-azd -e dfquickstart-dotnet
    

    此命令从模板存储库中拉取项目文件,并在当前文件夹中初始化项目。 -e 标志设置当前环境的名称。 在 azd,环境维护您应用程序的独特部署上下文,并且您可以定义多个。 环境名称还用于在 Azure 中创建的资源组的名称。

  2. 运行此命令以导航到 fanoutfanin 应用文件夹:

    cd fanoutfanin
    
  3. 在包含此 JSON 数据的 文件夹中创建名为 local.settings.json fanoutfanin的文件:

    {
        "IsEncrypted": false,
        "Values": {
            "AzureWebJobsStorage": "UseDevelopmentStorage=true",
            "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
        }
    }
    

    在本地运行时,需要此文件。

  1. 在本地终端或命令提示符下,在空文件夹中运行此 azd init 命令:

    azd init --template durable-functions-quickstart-python-azd -e dfquickstart-python
    

    此命令从模板存储库中拉取项目文件,并在当前文件夹中初始化项目。 -e 标志设置当前环境的名称。 在 azd,环境维护您应用程序的独特部署上下文,并且您可以定义多个。 环境名称还用于在 Azure 中创建的资源组的名称。

  2. 运行此命令以导航到 src 应用文件夹:

    cd src
    
  3. 在包含此 JSON 数据的 文件夹中创建名为 local.settings.json src的文件:

    {
        "IsEncrypted": false,
        "Values": {
            "AzureWebJobsStorage": "UseDevelopmentStorage=true",
            "FUNCTIONS_WORKER_RUNTIME": "python"
        }
    }
    

    在本地运行时,需要此文件。

创建并激活虚拟环境

src 文件夹中,运行以下命令来创建并激活名为 .venv 的虚拟环境:

python3 -m venv .venv
source .venv/bin/activate

如果 Python 未在 Linux 分发版上安装 venv 包,请运行以下命令:

sudo apt-get install python3-venv

安装 Python 依赖项

src在激活虚拟环境的文件夹中,运行以下命令以安装所需的依赖项:

pip install -r requirements.txt
  1. 在本地终端或命令提示符下,在空文件夹中运行此 azd init 命令:

    azd init --template durable-functions-quickstart-typescript-azd -e dfquickstart-typescript
    

    此命令从模板存储库中拉取项目文件,并在当前文件夹中初始化项目。 -e 标志设置当前环境的名称。 在 azd,环境维护您应用程序的独特部署上下文,并且您可以定义多个。 环境名称还用于在 Azure 中创建的资源组的名称。

  2. 运行此命令以导航到 src 应用文件夹:

    cd src
    
  3. 在包含此 JSON 数据的 文件夹中创建名为 local.settings.json src的文件:

    {
        "IsEncrypted": false,
        "Values": {
            "AzureWebJobsStorage": "UseDevelopmentStorage=true",
            "FUNCTIONS_WORKER_RUNTIME": "node"
        }
    }
    

    在本地运行时,需要此文件。

安装依赖项

src从文件夹中运行以下命令以安装所需的依赖项并生成项目:

npm install
npm run build

启动 Azurite

Functions 运行时需要存储组件。 "AzureWebJobsStorage": "UseDevelopmentStorage=true"local.settings.json 文件中的设置指示运行时使用本地存储模拟器 Azurite。

运行以下命令以启动 Azurite:

npx azurite --skipApiVersionCheck --location ~/azurite-data

使 Azurite 在终端窗口中保持运行。 在本地测试时需要它运行。

在本地环境中运行

  1. fanoutfanin从新终端窗口中的文件夹运行以下命令以启动 Functions 主机:

    func start
    

    当 Functions 主机在本地项目文件夹中启动时,它会将 HTTP 触发函数的本地 URL 终结点写入终端输出。

    注释

    由于在本地运行时不会强制实施访问密钥授权,因此无需访问密钥来调用函数。

  2. 在浏览器中,向启动业务流程的终结点发出 GET 请求:

    http://localhost:7071/api/FetchOrchestration_HttpStart

    此请求启动新的编排实例。 编排分配到多个活动,以并行获取 Microsoft Learn 文章的标题。 活动完成后,协调器回归并以格式化字符串的形式返回标题。

  1. 在激活虚拟环境的新的终端窗口中,从src文件夹运行以下命令以启动 Functions 的主机:

    func start
    

    当 Functions 主机在本地项目文件夹中启动时,它会将 HTTP 触发函数的本地 URL 终结点写入终端输出。

    注释

    由于在本地运行时不会强制实施访问密钥授权,因此无需访问密钥来调用函数。

  2. 在浏览器中,向 HTTP 启动终结点发出 GET 请求:

    http://localhost:7071/api/orchestrators/fetch_orchestration

    此请求启动新的编排实例。 编排分配到多个活动,以并行获取 Microsoft Learn 文章的标题。 活动完成后,协调器回归并以格式化字符串的形式返回标题。

  1. 在激活虚拟环境的新的终端窗口中,从src文件夹运行以下命令以启动 Functions 的主机:

    func start
    

    当 Functions 主机在本地项目文件夹中启动时,它会将 HTTP 触发函数的本地 URL 终结点写入终端输出。

    注释

    由于在本地运行时不会强制实施访问密钥授权,因此无需访问密钥来调用函数。

  2. 在浏览器中,向 HTTP 启动终结点发出 GET 请求:

    http://localhost:7071/api/orchestrators/fetchOrchestration

    此请求启动新的编排实例。 编排分配到多个活动,以并行获取 Microsoft Learn 文章的标题。 活动完成后,协调器回归并以格式化字符串的形式返回标题。

  1. HTTP 终结点返回包含多个 URL 的 JSON 响应。 端点 statusQueryGetUri 提供编排状态。

  2. statusQueryGetUri值复制并粘贴到浏览器或 HTTP 测试工具中,以检查编排的状态。 在编排完成后,您可以在响应结果中看到提取的文章标题。

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

  1. 运行 deactivate 以关闭虚拟环境。

查看代码(可选)

可以查看实现扇出/扇入模式的代码:

游戏提取活动使用动态任务列表进行跟踪。 该行 await Task.WhenAll(parallelTasks); 等待所有同时运行的已调用活动完成。 完成后,所有输出将聚合为格式化字符串。

        [Function(nameof(FetchOrchestration))]
        public static async Task<string> RunOrchestrator(
            [OrchestrationTrigger] TaskOrchestrationContext context)
        {
            ILogger logger = context.CreateReplaySafeLogger(nameof(FetchOrchestration));
            logger.LogInformation("Fetching data.");
            var parallelTasks = new List<Task<string>>();

            // List of URLs to fetch titles from
            var urls = new List<string>
            {
                "/azure-functions/durable/durable-functions-overview",
                "/azure-functions/durable/durable-task-scheduler/durable-task-scheduler",
                "/azure-functions/functions-scenarios",
                "/azure-functions/functions-create-ai-enabled-apps",
            };

            // Run fetching tasks in parallel
            foreach (var url in urls)
            {
                Task<string> task = context.CallActivityAsync<string>(nameof(FetchTitleAsync), url);
                parallelTasks.Add(task);
            }

            // Wait for all the parallel tasks to complete before continuing
            await Task.WhenAll(parallelTasks);

            // Return fetched titles as a formatted string
            return string.Join("; ", parallelTasks.Select(t => t.Result));
        }

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

游戏提取活动使用动态任务列表进行跟踪。 该行 yield context.task_all(tasks) 等待所有同时运行的已调用活动完成。 完成后,所有输出将聚合为格式化字符串。

    # List of URLs to fetch titles from
    urls = [
        "/azure-functions/durable/durable-functions-overview",
        "/azure-functions/durable/durable-task-scheduler/durable-task-scheduler",
        "/azure-functions/functions-scenarios",
        "/azure-functions/functions-create-ai-enabled-apps",
    ]

    # Run fetching tasks in parallel
    tasks = []
    for url in urls:
        task = context.call_activity("fetch_title", url)
        tasks.append(task)

    # Wait for all the parallel tasks to complete before continuing
    results = yield context.task_all(tasks)

    # Return fetched titles as a formatted string
    return "; ".join(results)


@myApp.activity_trigger(input_name="url")
async def fetch_title(url: str):
    """Activity function that fetches the title from a URL."""
    logger = logging.getLogger("FetchTitle")
    logger.info(f"Fetching from url {url}.")

    try:
        async with ClientSession() as session:

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

游戏提取活动使用动态任务列表进行跟踪。 该行 yield context.df.Task.all(parallelTasks) 等待所有同时运行的已调用活动完成。 完成后,所有输出将聚合为格式化字符串。

    const urls = [
        "/azure-functions/durable/durable-functions-overview",
        "/azure-functions/durable/durable-task-scheduler/durable-task-scheduler",
        "/azure-functions/functions-scenarios",
        "/azure-functions/functions-create-ai-enabled-apps",
    ];

    // Run fetching tasks in parallel
    const parallelTasks = [];
    for (const url of urls) {
        const task = context.df.callActivity(fetchTitleActivityName, url);
        parallelTasks.push(task);
    }

    // Wait for all the parallel tasks to complete before continuing
    const results: string[] = yield context.df.Task.all(parallelTasks);

    // Return fetched titles as a formatted string
    return results.join("; ");
};
df.app.orchestration("fetchOrchestration", fetchOrchestration);

const fetchTitleAsync: ActivityHandler = async function (
    url: string,
    context: InvocationContext

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

在本地验证函数后,可以将其发布到 Azure。

部署到 Azure 云

此项目配置为使用 azd up 命令(从项目根文件夹运行)将此项目部署到 Azure 中的 Flex Consumption 计划中的新函数应用。

小窍门

该项目包括一组 Bicep 文件(在 infra 文件夹中), azd 用于创建安全部署到遵循最佳做法的 Flex 消耗计划。

  1. 在包含 azure.yaml 文件的项目根文件夹中,运行以下命令以使用 Azure 帐户进行身份验证:

    azd auth login
    
  2. 对于本快速入门,请运行以下命令以禁用虚拟网络部署:

    azd env set VNET_ENABLED false
    
  3. 从根项目文件夹中运行以下命令,创建 azd 所需的 Azure 资源并将代码项目部署到新的函数应用:

    azd up
    

    根文件夹包含 azure.yaml 所需的 azd 定义文件。

  4. 出现提示时,请提供以下所需的部署参数:

    参数 Description
    Azure 订阅 要在其中创建资源的订阅。
    Azure 位置 要在其中创建包含新 Azure 资源的资源组的 Azure 区域。 仅显示当前支持 Flex 消耗计划的区域。

    azd up 命令结合你对这些提示的回答和 Bicep 配置文件来完成这些部署任务:

    • 创建并配置这些所需的 Azure 资源:

      • Flex 消耗计划和函数应用
      • Azure 存储(必需)和 Application Insights(推荐)
      • 帐户的访问策略和角色
      • 使用托管标识(而不是存储的连接字符串)的服务到服务连接
    • 打包代码并将其部署到部署容器。 然后,应用将启动并在已部署的包中运行。

    命令成功完成后,你会看到指向所创建资源的链接。

在 Azure 上调用函数

现在,可以通过向 Azure 中的业务流程终结点发出 HTTP 请求来调用其 URL。 函数在 Azure 中运行时,系统将强制实施访问密钥授权,你必须向请求提供函数访问密钥。

可以使用 Core Tools 获取在 Azure 中启动业务流程的 HTTP 触发器的 URL 终结点。

  1. 在本地终端或命令提示符下,运行以下命令以获取 URL 终结点值:

    APP_NAME=$(azd env get-value AZURE_FUNCTION_NAME)
    func azure functionapp list-functions $APP_NAME --show-keys
    

    azd env get-value 命令从本地环境中获取函数应用名称。 将 --show-keys 选项与 func azure functionapp list-functions 结合使用时,每个终结点返回的 调用 URL: 值包括任何必需的函数级访问密钥。

  2. 与以前一样,使用浏览器或 HTTP 测试工具在 Azure 中运行的函数应用中启动业务流程。

重新部署代码

azd up根据需要多次运行命令,以便预配 Azure 资源并将代码更新部署到函数应用。

注释

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

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

清理资源

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

azd down --no-prompt

注释

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

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