练习 - 添加持久计时器,管理长时间运行的任务

已完成

公司已要求修改新的工作流,合并升级步骤,使工作流在项目设计提案未及时获得批准时采取措施。

在此练习中,将添加计时器,用于控制工作流执行期间的超时。 此外还介绍如何使用超时控制工作流采用的执行路径。

将 moment npm 包添加到函数应用

更改工作流之前,通过控制台将 moment npm 包添加到函数应用。

  1. 使用激活沙盒时所用的同一帐户登录到 Azure 门户

  2. 在 Azure 门户菜单上或在主页中,选择“Azure 服务”下的“所有资源”,然后选择在前面的练习中创建的函数应用。 系统将显示函数应用窗格。

  3. 在左侧菜单栏中的“开发工具”下,选择“控制台”。 此时将显示函数应用的“控制台”窗格。

  4. 验证控制台窗口是否在 C:\home\site\wwwroot 文件夹中打开,并运行以下命令来安装此示例函数应用所需的库。

    1. 运行以下命令以安装 TypeScript 库,这是静态类型化所必需的依赖项。

      npm install typescript
      
    2. 运行以下命令安装 moment 库,该库包含可与持久性函数配合使用的 date/time 函数。

      npm install moment
      

      这些命令可能需要几秒钟才能完成,并且节点包管理器可能会显示一些可忽略的警告。

  5. 等待所有包完成安装,然后关闭控制台窗口。

将升级活动添加到函数应用

  1. 在 Azure 门户菜单上或在主页中,选择“Azure 服务”下的“所有资源”,然后选择函数应用。 系统将显示函数应用窗格。

  2. 选择屏幕中间的函数选项卡。

  3. 在“函数”选项卡菜单栏中,选择“创建”。 此时将显示“创建函数”窗格。

  4. 在“选择模板”下的“筛选器”框中,输入“Durable Functions 活动”,然后从列表中选择该模板。 此模板创建一个持久函数,该函数在业务流程协调程序函数调用活动时运行。

  5. 在“模板详细信息”下,对于“新建函数”字段,输入“Escalation”作为函数名称,然后选择“创建”。 此时将显示函数的“升级”窗格。

  6. 在左侧菜单窗格的“开发人员”下,选择“代码 + 测试”。 此时,函数的“代码和测试”窗格显示。

    此时将在编辑器中显示 index.js 文件的代码。

  7. 将现有代码替换为以下代码:

    module.exports = async function (context) {
        return `ESCALATION : You have not approved the project design proposal - reassigning to your Manager!  ${context.bindings.name}!`;
    };
    

    此代码返回一条指示工作流已升级的消息。 在生产系统中,此函数包含用于提醒收件人或重新分配任务的逻辑。

  8. 在顶部菜单栏中,选择“保存”以保存新函数。

更新业务流程函数,使其能使用升级函数

  1. 在 Azure 门户菜单上或在主页中,选择“Azure 服务”下的“所有资源”,然后选择函数应用。 系统将显示函数应用窗格。

  2. 选择屏幕中间的函数选项卡。

  3. 选择在前面的练习中创建的“OrchFunction”函数。 此时将显示“OrchFunction”函数窗格。

  4. 在左侧菜单窗格的“开发人员”下,选择“代码 + 测试”。 此时,函数的“代码和测试”窗格显示。

    此时将在编辑器中显示 index.js 文件的代码。

  5. 添加对 moment 库的以下引用。

    const moment = require("moment");
    
  6. 将函数的主体替换为以下代码,该代码将测试是否已超过审批的截止时间。

    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”的调用,使其等待外部输入。 通过此操作,可以出于测试目的来控制响应的返回时间。

  7. 在顶部菜单栏中,选择“保存”。

确认 Durable Functions 工作流启动

  1. 在 Azure 门户菜单上或在主页中,选择“Azure 服务”下的“所有资源”,然后选择函数应用。 系统将显示函数应用窗格。

  2. 在“概述”窗格的顶部菜单栏中,选择“重新启动”,然后在系统提示重新启动时选择“是”。 等待重启过程完成,然后继续。 此时将显示“函数应用”窗格。

  3. 选择屏幕中间的函数选项卡。

  4. 选择“HttpStart”函数。 此时将显示“HttpStart”窗格。

  5. 在顶部菜单栏中,选择“获取函数 URL”,然后复制 URL。 URL 应与下面的示例类似:

    https://example.azurewebsites.net/api/orchestrators/{functionName}?code=AbCdEfGhIjKlMnOpQrStUvWxYz==
    

    将使用此 URL 运行函数。

  6. 打开新浏览器窗口,并导航到已复制的 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/..."
    }
    
  7. 复制 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"
    }
    
  8. 等待 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"
    }