练习 - 使用 Durable Functions 创建工作流
在此练习中,你使用上一个单元的示例场景来了解如何在 Azure 门户中使用 Durable Functions 创建审批工作流。
创建函数应用
使用激活沙盒时所用的同一帐户登录到 Azure 门户。
在 Azure 门户菜单上或在“主页”中,选择“Azure 服务”下的“创建资源”。 此时会显示“创建资源”窗格。
搜索并选择“函数应用”。 此时将显示“创建函数应用”窗格。
在“基本信息”选项卡上,为每个设置输入以下值。
设置 值 说明 项目详细信息 订阅 Concierge 订阅 指定要在其下创建此新函数应用的订阅。 资源组 从下拉列表中,选择 [沙盒资源组名称] 指定要在其中创建函数应用的资源组的名称。 我们将在激活沙盒时分配的沙盒资源组(即 [沙盒资源组名称] )中创建函数应用。实例详细信息 Function App 名称 [全局唯一名称] 指定用于标识新函数应用的名称。 有效字符为 a-z
、0-9
和-
。发布 代码 指定函数使用代码而不是容器。 运行时堆栈 Node.js 指定使用 JavaScript 编写此模块中的示例代码。 版本 20 LTS 指定运行时堆栈的版本。 区域 [从本部分后面的列表中选择] 选择离你最近且属于下面允许的沙盒区域的位置。 操作系统 操作系统 Windows 指定用于托管函数应用的操作系统。 规划 计划类型 消耗(无服务器) 指定托管计划,用于定义如何将资源分配给函数应用。 在默认“消耗计划”中,会根据函数的需求动态添加资源。 在此无服务器托管模型中,只需根据函数的运行时间付费。 使用免费沙盒,可以在部分 Azure 全球区域中创建资源。 创建资源时,请从下面的列表中选择一个区域:
- 美国西部 2
- 美国中南部
- 美国中部
- 美国东部
- 西欧
- 东南亚
- Japan East
- Brazil South
- Australia Southeast
- 印度中部
选择“下一页:存储”。
在“存储”选项卡上,为每个设置输入以下值。
设置 值 说明 存储 存储帐户 [全局唯一名称] 指定函数应用使用的新存储帐户的名称(不需要与为函数指定的全局唯一名称匹配)。 存储帐户名称必须为 3 到 24 个字符,并且只能包含数字和小写字母。 此对话框使用动态生成的唯一名称自动填充字段。 但是,可以任意使用不同的名称,甚至是现有帐户名称。 选择“下一页:网络”。 接受默认值。
选择“下一步: 监视”。
在“监视”选项卡上,为设置输入以下值。
设置 值 说明 Application Insights 启用 Application Insights 否 指定对此模块禁用 Application Insights。 选择“查看和创建”,查看已配置的选项。 如果对选项感到满意,则选择“创建”来预配和部署函数应用。
等待部署完成,然后继续。 部署可能需要几分钟时间。
安装 durable-functions npm 包
我们要创建 JavaScript Durable Functions,所以需要安装 durable-functions
npm 包。 为此,请执行下列步骤。
选择“转到资源”以选择函数应用。 系统将显示函数应用窗格。
在左侧菜单窗格中的“开发工具”下,选择“应用服务编辑器(预览)”,然后选择“打开编辑器”。 此时将在新的浏览器窗口中显示“应用服务编辑器”快速入门窗格。
在左侧菜单窗格中,突出显示 WWWROOT 文件夹。
在左侧工具栏菜单中,选择“打开控制台”图标。
此操作将启动控制台。 可使用此控制台访问托管函数的 Web 服务器,并为该函数编写代码。
创建新的“package.json”文件。
在控制台中运行以下命令,创建新的 JSON 文件,并在编辑器中将其打开。
touch package.json open package.json
添加以下代码。
{ "name": "example", "version": "1.0.0" }
将
example
替换为包的名称。 例如,可以使用先前为函数指定的全局唯一名称。
选择 Ctrl+S 保存文件,然后选择 Ctrl+Q 关闭文档。
切换回 Azure 门户。
在左侧菜单栏中的“开发工具”下,选择“控制台”。 此时将显示函数应用的“控制台”窗格。
运行以下命令:
npm install durable-functions
此命令指示节点包管理器安装
durable-functions
包和任何必需的依赖项。 安装可能需要几分钟才能完成,并且节点包管理器可能会显示一些警告(可忽略这些警告)。 如果系统提示安装较新版本的 npm,请使用错误中提供的命令安装较新版本,然后在安装新版本后安装durable-functions
包。等待所有包完成安装。
在左侧菜单窗格中,向上滚动并选择“概述”,然后在顶部菜单栏中选择“重新启动”,并在系统提示是否重新启动时选择“是”。
等待重启过程完成,然后继续。
创建用于提交设计提案的客户端函数
在 Azure 门户菜单或主页的“最近使用的资源”下,选择“查看全部”,然后选择你的函数应用。 系统将显示函数应用窗格。
在“概述”页上,选择屏幕中间的“函数”选项卡。
选择“在 Azure 门户中创建”按钮。 此时将显示“创建函数”窗格。
在“选择模板”下的“筛选器”框中,输入“Durable Functions HTTP starter”,然后从列表中选择该模板。 此模板创建持久函数,用于响应 HTTP 请求。
在“模板详细信息”下,对于“新建函数”字段,输入“HttpStart”作为函数名称,在“授权级别”字段中,选择“函数”,然后选择“创建”。 此时将显示函数的“HttpStart”窗格。
在左侧菜单窗格的“开发人员”下,选择“代码 + 测试”。 此时,函数的“代码和测试”窗格显示。
此时将在编辑器中显示 index.js 文件的代码。 文件应与下面的示例类似:
const df = require("durable-functions"); module.exports = async function (context, req) { const client = df.getClient(context); const instanceId = await client.startNew(req.params.functionName, undefined, req.body); context.log(`Started orchestration with ID = '${instanceId}'.`); return client.createCheckStatusResponse(context.bindingData.req, instanceId); };
在函数中的文件的下拉列表中,选择“function.json”以查看与新函数关联的绑定。 此信息指定任何身份验证要求,以及触发该函数的 HTTP 方法。 此文件还指定该函数是启动业务流程进程的客户端。 文件应与下面的示例类似:
{ "bindings": [ { "authLevel": "function", "name": "req", "type": "httpTrigger", "direction": "in", "route": "orchestrators/{functionName}", "methods": [ "post", "get" ] }, { "name": "$return", "type": "http", "direction": "out" }, { "name": "starter", "type": "orchestrationClient", "direction": "in" } ] }
注意
绑定将触发器的资源和其他项相关联。 绑定是一种声明性机制,无需将引用硬编码到代码中的其他服务和函数。
创建业务流程协调函数
在 Azure 门户菜单或主页的“最近使用的资源”下,选择“查看全部”,然后选择你的函数应用。 系统将显示函数应用窗格。
在“概述”页上,选择屏幕中间的“函数”选项卡。
在“函数”菜单栏中,选择“创建”。 此时将显示“创建函数”窗格。
在“选择模板”下的“筛选器”框中,输入“Durable Functions orchestrator”,然后从列表中选择该模板。 此模板创建持久函数,用于协调函数的执行。
在“模板详细信息”下,对于“新建函数”字段,输入“OrchFunction”作为函数名称,然后选择“创建”。 此时将显示“OrchFunction”函数窗格。
在左侧菜单窗格的“开发人员”下,选择“代码 + 测试”。 此时,函数的“代码和测试”窗格显示。
此时将在编辑器中显示 index.js 文件的代码。
用下面的代码替换现有代码。
const df = require("durable-functions"); module.exports = df.orchestrator(function* (context) { const outputs = []; /* * We will call the approval activity with a reject and an approved to simulate both */ outputs.push(yield context.df.callActivity("Approval", "Approved")); outputs.push(yield context.df.callActivity("Approval", "Rejected")); return outputs; });
此代码调用名为“Approval”的 Activity 函数,稍后会创建该函数。 业务流程协调程序函数中的代码调用 Approval 函数两次。 第一次模拟“接受提案”,第二次测试“提案拒绝”逻辑。
每次调用返回的值组合在一起,并传回客户端函数。 在生产环境中,业务流程函数调用一系列活动函数,用于作出接受/拒绝决定,并返回这些活动的结果。
在顶部菜单栏中,选择“保存”以保存新函数。
创建活动函数
在 Azure 门户菜单或主页的“最近使用的资源”下,选择“查看全部”,然后选择你的函数应用。 系统将显示函数应用窗格。
在“概述”页上,选择屏幕中间的“函数”选项卡。
在“函数”菜单栏中,选择“创建”。 此时将显示“创建函数”窗格。
在“选择模板”下的“筛选器”框中,输入“Durable Functions activity”,然后从列表中选择该模板。 此模板创建一个持久函数,该函数在业务流程协调程序函数调用活动时运行。
在“模板详细信息”下,对于“新建函数”字段,输入“Approval”作为函数名称,然后选择“创建”。 此时将显示函数应用的“批准”窗格。
在左侧菜单窗格的“开发人员”下,选择“代码 + 测试”。 此时,函数的“代码和测试”窗格显示。
此时将在编辑器中显示 index.js 文件的代码。
用下面的代码替换现有代码。
module.exports = async function (context) { return `Your project design proposal has been - ${context.bindings.name}!`; };
此函数返回一条指示提案状态的消息。 表达式
context.bindings.name
的结果是Accepted
或Rejected
,具体取决于从业务流程协调程序传递到函数的参数。 在真实世界的方案中,需要在此函数中添加用于处理接受或拒绝操作的逻辑。在顶部菜单栏中,选择“保存”以保存新函数。
确认 Durable Functions 工作流启动
在 Azure 门户菜单或主页的“最近使用的资源”下,选择“查看全部”,然后选择你的函数应用。 系统将显示函数应用窗格。
选择页面中间的“函数”选项卡。
选择“HttpStart”函数。 此时将显示函数的“HttpStart”窗格。
在顶部菜单栏中,选择“获取函数 URL”,然后复制 URL。 URL 应与下面的示例类似:
https://example.azurewebsites.net/api/orchestrators/{functionName}?code=AbCdEfGhIjKlMnOpQrStUvWxYz==
使用此 URL 运行函数。
打开新浏览器窗口,并转到已复制的 URL。 在 URL 中,将 {functionName} 占位符替换为 OrchFunction,这应类似于以下示例:
https://example.azurewebsites.net/api/orchestrators/OrchFunction?code=AbCdEfGhIjKlMnOpQrStUvWxYz==
响应消息包含一组 URI 终结点,这些终结点可以用来监视并管理执行,该执行应与以下示例类似:
{ "id": "f0e1d2c3b4a5968778695a4b3c2d1e0f", "statusQueryGetUri": "https://example.azurewebsites.net/...", "sendEventPostUri": "https://example.azurewebsites.net/...", "terminatePostUri": "https://example.azurewebsites.net/...", "rewindPostUri": "https://example.azurewebsites.net/...", "purgeHistoryDeleteUri": "https://example.azurewebsites.net/..." }
复制 statusQueryGetUri 值,并使用 Web 浏览器转到此 URL。 应看到类似于以下示例的响应消息:
{ "name": "OrchFunction", "instanceId": "f0e1d2c3b4a5968778695a4b3c2d1e0f", "runtimeStatus": "Completed", "input": null, "customStatus": null, "output": [ "Your project design proposal has been - Approved!", "Your project design proposal has been - Rejected!" ], "createdTime": "2019-04-16T15:23:03Z", "lastUpdatedTime": "2019-04-16T15:23:35Z" }
前面曾提到,业务流程函数运行两次活动函数。 第一次,Activity 函数指示已接受项目提案。 第二次运行,提案被拒绝。 业务流程函数将这两个函数调用中的消息合并,然后将其返回到客户端函数。