练习 - 添加持久计时器,管理长时间运行的任务
公司已要求修改新的工作流,合并升级步骤,使工作流在项目设计提案未及时获得批准时采取措施。
在此练习中,将添加计时器,用于控制工作流执行期间的超时。 此外还介绍如何使用超时控制工作流采用的执行路径。
将 moment npm 包添加到函数应用
更改工作流之前,通过控制台将 moment npm 包添加到函数应用。
使用激活沙盒时所用的同一帐户登录到 Azure 门户。
在 Azure 门户菜单上或在主页中,选择“Azure 服务”下的“所有资源”,然后选择在前面的练习中创建的函数应用。 系统将显示函数应用窗格。
在左侧菜单栏中的“开发工具”下,选择“控制台”。 此时将显示函数应用的“控制台”窗格。
验证控制台窗口是否在 C:\home\site\wwwroot 文件夹中打开,并运行以下命令来安装此示例函数应用所需的库。
运行以下命令以安装 TypeScript 库,这是静态类型化所必需的依赖项。
npm install typescript
运行以下命令安装 moment 库,该库包含可与持久性函数配合使用的 date/time 函数。
npm install moment
这些命令可能需要几秒钟才能完成,并且节点包管理器可能会显示一些可忽略的警告。
等待所有包完成安装,然后关闭控制台窗口。
将升级活动添加到函数应用
在 Azure 门户菜单上或在主页中,选择“Azure 服务”下的“所有资源”,然后选择函数应用。 系统将显示函数应用窗格。
选择屏幕中间的函数选项卡。
在“函数”选项卡菜单栏中,选择“创建”。 此时将显示“创建函数”窗格。
在“选择模板”下的“筛选器”框中,输入“Durable Functions activity”,然后从列表中选择该模板。 此模板创建一个持久函数,该函数在业务流程协调程序函数调用活动时运行。
在“模板详细信息”下,对于“新建函数”字段,输入“Escalation”作为函数名称,然后选择“创建”。 此时将显示函数的“升级”窗格。
在左侧菜单窗格的“开发人员”下,选择“代码 + 测试”。 此时,函数的“代码和测试”窗格显示。
此时将在编辑器中显示 index.js 文件的代码。
将现有代码替换为以下代码:
module.exports = async function (context) { return `ESCALATION : You have not approved the project design proposal - reassigning to your Manager! ${context.bindings.name}!`; };
此代码返回一条指示工作流已升级的消息。 在生产系统中,此函数包含用于提醒收件人或重新分配任务的逻辑。
在顶部菜单栏中,选择“保存”以保存新函数。
更新业务流程函数,使其能使用升级函数
在 Azure 门户菜单上或在主页中,选择“Azure 服务”下的“所有资源”,然后选择函数应用。 系统将显示函数应用窗格。
选择屏幕中间的函数选项卡。
选择在前面的练习中创建的“OrchFunction”函数。 此时将显示“OrchFunction”函数窗格。
在左侧菜单窗格的“开发人员”下,选择“代码 + 测试”。 此时,函数的“代码和测试”窗格显示。
此时将在编辑器中显示 index.js 文件的代码。
添加对 moment 库的以下引用。
const moment = require("moment");
将函数的主体替换为以下代码,该代码将测试是否已超过审批的截止时间。
module.exports = df.orchestrator(function* (context) { const outputs = []; const deadline = moment.utc(context.df.currentUtcDateTime).add(20, "s"); const activityTask = context.df.waitForExternalEvent("Approval"); const timeoutTask = context.df.createTimer(deadline.toDate()); const winner = yield context.df.Task.any([activityTask, timeoutTask]); if (winner === activityTask) { outputs.push(yield context.df.callActivity("Approval", "Approved")); } else { outputs.push(yield context.df.callActivity("Escalation", "Head of department")); } if (!timeoutTask.isCompleted) { // All pending timers must be complete or canceled before the function exits. timeoutTask.cancel(); } return outputs; });
为简化此练习,如果“Approval”函数未在 20 秒内响应,则调用“Escalation”函数。 代码也会更改对“Approval”的调用,使其等待外部输入。 通过此操作,可以出于测试目的来控制响应的返回时间。
在顶部菜单栏中,选择“保存”。
确认 Durable Functions 工作流启动
在 Azure 门户菜单上或在主页中,选择“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。 你应该会看到一条响应消息,它会显示状态为“正在运行”,同时正在等待计时器倒计时 20 秒,这应类似于以下示例:
{ "name": "OrchFunction", "instanceId": "f0e1d2c3b4a5968778695a4b3c2d1e0f", "runtimeStatus": "Running", "input": null, "customStatus": null, "output": null, "createdTime": "2019-04-14T13:17:26Z", "lastUpdatedTime": "2019-04-14T13:17:27Z" }
等待 20 秒后刷新浏览器窗口。 超时时间应该已经达到,工作流将调用“升级”活动。 应会看到类似以下的响应:
{ "name": "OrchFunction", "instanceId": "f0e1d2c3b4a5968778695a4b3c2d1e0f", "runtimeStatus": "Completed", "input": null, "customStatus": null, "output": [ "ESCALATION : You have not approved the project design proposal - reassigning to your Manager! Head of department!" ], "createdTime": "2019-04-14T13:43:09Z", "lastUpdatedTime": "2019-04-14T13:43:31Z" }