

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 在 Step Functions 中检查状态机执行
<a name="debug-sm-exec-using-ui"></a>

在本教程中，您将学习如何检查*执行详细信息* 页面上显示的执行信息并查看执行失败的原因。然后，您将学习如何访问 `Map` 状态执行的不同迭代。最后，您将学习如何在**表格视图**上配置列，以及如何应用合适的筛选条件来仅查看您感兴趣的信息。

在本教程中，您将创建一个标准类型的状态机，用于获取一组水果的价格。为此，状态机使用三个 AWS Lambda 函数，分别返回四个水果的随机列表、每种水果的价格以及水果的平均成本。如果水果的价格小于或等于阈值，Lambda 函数就会出错。

**注意**  
虽然以下过程包含有关如何检查标准工作流执行详细信息的说明，但您也可以检查快速工作流执行的详细信息。有关标准工作流和快速工作流类型执行详细信息的差异，请参阅[标准和快速控制台体验的差别](concepts-view-execution-details.md#console-exp-differences)。

## 第 1 步：创建并测试所需的 Lambda 函数
<a name="step-create-all-lambda-functions"></a>

1. 打开 [Lambda 控制台](https://console.aws.amazon.com/lambda/home)，然后执行[第 1 步：创建 Lambda 函数](tutorial-creating-lambda-state-machine.md#create-lambda-function)部分中的第 1 步至第 4 步。确保将 Lambda 函数命名为 **GetListOfFruits**。

1. 创建 Lambda 函数后，复制页面右上角显示的函数 Amazon 资源名称 (ARN)。要复制 ARN，请单击复制图标以复制 Lambda 函数的 Amazon 资源名称。以下是一个 ARN 示例，其中 *`function-name`* 是 Lambda 函数的名称（在本例中为 `GetListOfFruits`）：

   ```
   arn:aws:lambda:region:123456789012:function:function-name
   ```

1. 将以下 Lambda 函数的代码复制到 **GetListOfFruits** 页面的**代码源**区域中。

   ```
   function getRandomSubarray(arr, size) {
       var shuffled = arr.slice(0), i = arr.length, temp, index;
       while (i--) {
           index = Math.floor((i + 1) * Math.random());
           temp = shuffled[index];
           shuffled[index] = shuffled[i];
           shuffled[i] = temp;
       }
       return shuffled.slice(0, size);
   }
   
   exports.handler = async function(event, context) {
       
       const fruits = ['Abiu','Açaí','Acerola','Ackee','African cucumber','Apple','Apricot','Avocado','Banana','Bilberry','Blackberry','Blackcurrant','Jostaberry'];
   
       
        const errorChance = 45;
       
       const waitTime = Math.floor( 100 * Math.random() );
   
       await new Promise( r => setTimeout(() => r(), waitTime));
   
       const num = Math.floor( 100 * Math.random() );
       // const num = 51;
        if (num <= errorChance) {
            throw(new Error('Error'));
        }
   
       return getRandomSubarray(fruits, 4);
   };
   ```

1. 选择**部署**，然后选择**测试**，部署更改并查看 Lambda 函数的输出。

1. 按照以下步骤创建另外两个 Lambda 函数，分别命名为 **GetFruitPrice** 和 **CalculateAverage**：

   1. 将以下代码复制到 **GetFruitPrice** Lambda 函数的**代码源**区域中：

      ```
      exports.handler = async function(event, context) {
          
          const errorChance = 0;
          const waitTime = Math.floor( 100 * Math.random() );
      
          await new Promise( r => setTimeout(() => r(), waitTime));
      
          const num = Math.floor( 100 * Math.random() );
          if (num <= errorChance) {
              throw(new Error('Error'));
          }
      
          return Math.floor(Math.random()*100)/10;
      };
      ```

   1. 将以下代码复制到 **CalculateAverage** Lambda 函数的**代码源**区域中：

      ```
      function getRandomSubarray(arr, size) {
          var shuffled = arr.slice(0), i = arr.length, temp, index;
          while (i--) {
              index = Math.floor((i + 1) * Math.random());
              temp = shuffled[index];
              shuffled[index] = shuffled[i];
              shuffled[i] = temp;
          }
          return shuffled.slice(0, size);
      }
      
      const average = arr => arr.reduce( ( p, c ) => p + c, 0 ) / arr.length;
          
      exports.handler = async function(event, context) {
              const errors = [
              "Error getting data from DynamoDB",
              "Error connecting to DynamoDB",
              "Network error",
              "MemoryError - Low memory"
              ]
              
          const errorChance = 0;
          
          const waitTime = Math.floor( 100 * Math.random() );
      
          await new Promise( r => setTimeout(() => r(), waitTime));
      
          const num = Math.floor( 100 * Math.random() );
          if (num <= errorChance) {
              throw(new Error(getRandomSubarray(errors, 1)[0]));
          }
      
          return average(event);
      };
      ```

   1. 确保复制这两个 Lambda 函数的 ARN，然后对其进行**部署**和**测试**。

## 第 2 步：创建并执行状态机
<a name="step-create-exec-sm"></a>

使用 [Step Functions 控制台](https://console.aws.amazon.com/states/home?region=us-east-1#/)创建状态机，用于调用[您在第 1 步中创建的 Lambda 函数](#step-create-all-lambda-functions)。在此状态机中，定义三个 `Map` 状态。每个 `Map` 状态都包含一个调用 Lambda 函数的 `Task` 状态。此外，每个 `Task` 状态都定义了一个 `Retry` 字段，并为每个状态定义了重试次数。如果一个 `Task` 状态遇到运行时错误，则会再次执行该状态，但不得超过为此 `Task` 定义的重试次数。

1. 打开 [Step Functions 控制台](https://console.aws.amazon.com/states/home)，然后选择**用代码编写工作流**。
**重要**  
确保您的状态机与您之前创建的 Lambda 函数位于相同的 AWS 账户和区域下。

1. 对于**类型**，保留默认的**标准**选择。

1. 复制以下 Amazon States Language 定义并将其粘贴到**定义**下。确保将显示的 ARN 替换为您之前创建的 Lambda 函数的 ARN。

   ```
   {
       "StartAt": "LoopOverStores",
       "States": {
           "LoopOverStores": {
               "Type": "Map",
               "Iterator": {
                   "StartAt": "GetListOfFruits",
                   "States": {
                       "GetListOfFruits": {
                           "Type": "Task",
                           "Resource": "arn:aws:states:::lambda:invoke",
                           "OutputPath": "$.Payload",
                           "Parameters": {
                               "FunctionName": "arn:aws:lambda:region:123456789012:function:GetListofFruits:$LATEST",
                               "Payload": {
                                   "storeName.$": "$"
                               }
                           },
                           "Retry": [
                               {
                                   "ErrorEquals": [
                                       "States.ALL"
                                   ],
                                   "IntervalSeconds": 2,
                                   "MaxAttempts": 1,
                                   "BackoffRate": 1.3
                               }
                           ],
                           "Next": "LoopOverFruits"
                       },
                       "LoopOverFruits": {
                           "Type": "Map",
                           "Iterator": {
                               "StartAt": "GetFruitPrice",
                               "States": {
                                   "GetFruitPrice": {
                                       "Type": "Task",
                                       "Resource": "arn:aws:states:::lambda:invoke",
                                       "OutputPath": "$.Payload",
                                       "Parameters": {
                                           "FunctionName": "arn:aws:lambda:region:123456789012:function:GetFruitPrice:$LATEST",
                                           "Payload": {
                                               "fruitName.$": "$"
                                           }
                                       },
                                       "Retry": [
                                           {
                                               "ErrorEquals": [
                                                   "States.ALL"
                                               ],
                                               "IntervalSeconds": 2,
                                               "MaxAttempts": 3,
                                               "BackoffRate": 1.3
                                           }
                                       ],
                                       "End": true
                                   }
                               }
                           },
                           "ItemsPath": "$",
                           "End": true
                       }
                   }
               },
               "ItemsPath": "$.stores",
               "Next": "LoopOverStoreFruitsPrice",
               "ResultPath": "$.storesFruitsPrice"
           },
           "LoopOverStoreFruitsPrice": {
               "Type": "Map",
               "End": true,
               "Iterator": {
                   "StartAt": "CalculateAverage",
                   "States": {
                       "CalculateAverage": {
                           "Type": "Task",
                           "Resource": "arn:aws:states:::lambda:invoke",
                           "OutputPath": "$.Payload",
                           "Parameters": {
                               "FunctionName": "arn:aws:lambda:region:123456789012:function:Calculate-average:$LATEST",
                               "Payload.$": "$"
                           },
                           "Retry": [
                               {
                                   "ErrorEquals": [
                                       "States.ALL"
                                   ],
                                   "IntervalSeconds": 2,
                                   "MaxAttempts": 2,
                                   "BackoffRate": 1.3
                               }
                           ],
                           "End": true
                       }
                   }
               },
               "ItemsPath": "$.storesFruitsPrice",
               "ResultPath": "$.storesPriceAverage",
               "MaxConcurrency": 1
           }
       }
   }
   ```

1. 为状态机输入名称。保留本页其他选项的默认选项，然后选择**创建状态机**。

1. 打开标题为状态机名称的页面。执行[第 4 步：运行状态机](tutorial-creating-lambda-state-machine.md#start-lambda-function)部分中的第 1 步至第 4 步，但使用以下数据作为执行输入：

   ```
   {
       "stores": [
         "Store A",
         "Store B",
         "Store C",
         "Store D"
       ]
   }
   ```

## 第 3 步：查看状态机执行详细信息
<a name="view-sm-exec-details"></a>

在标题为执行 ID 的页面上，您可以查看执行结果并调试任何错误。

1. （可选）从*执行详细信息* 页面上显示的选项卡中进行选择，查看每个选项卡中显示的信息。例如，要查看状态机输入及其执行输出，请在*[执行摘要](concepts-view-execution-details.md#exec-details-intf-exec-summ)* 部分选择**执行输入和输出**。

1. 如果状态机执行失败，请在错误消息上选择**原因**或**显示步骤详细信息**。有关错误的详细信息显示在*[步骤详细信息](concepts-view-execution-details.md#exec-details-intf-step-details)* 部分。请注意，导致错误的步骤（名为 **GetListofFruits** 的 `Task` 状态）在**图表视图**和**表格视图**中突出显示。
**注意**  
由于 **GetListofFruits** 步骤是在 `Map` 状态内定义的，而该步骤未能成功执行，因此 `Map` 状态步骤的**状态**显示为**失败**。

## 第 4 步：探索不同的*视图模式*
<a name="sm-exec-details-exp-view-modes"></a>

您可以选择首选模式来查看状态机工作流或执行事件历史记录。在这些*视图模式* 下可以执行的部分任务如下：

### **图表视图** – 在不同的 `Map` 状态迭代之间切换
<a name="graph-view-see-map-state-iterations"></a>

如果您的 **Map** 状态有五次迭代，并且您想要查看第三次和第四次迭代的执行详细信息，请执行以下操作：

1. 选择要查看其迭代数据的 `Map` 状态。

1. 在 **Map 迭代查看器**中，选择要查看的迭代。迭代从零开始计数。要从五次迭代中选择第三次迭代，请从 **Map** 状态名称旁边的下拉列表中选择 **\$12**。
**注意**  
如果状态机包含嵌套的 `Map` 状态，Step Functions 会将父和子 `Map` 状态迭代显示为两个单独的下拉列表（表示嵌套状态的迭代数据）。

1. （可选）如果一次或多次 `Map` 状态迭代未能执行或停止在中止状态，则可以查看有关失败迭代的详细信息。要查看这些详细信息，请在下拉列表的**失败**或**已中止**下选择受影响的迭代编号。

### **表格视图** – 在不同的 `Map` 状态迭代之间切换
<a name="table-view-see-map-state-iterations"></a>

如果您的 **Map** 状态有五次迭代，并且您想要查看第三次和第四次迭代的执行详细信息，请执行以下操作：

1. 选择要查看其不同迭代数据的 `Map` 状态。

1. 在 `Map` 状态迭代的树视图显示中，选择名为 **\$12** 的迭代行，打开第三次迭代。同样，选择名为 **\$13** 的行，打开第四次迭代。

### **表格视图** – 配置要显示的列
<a name="table-view-cfg-display-cols"></a>

选择设置图标。然后，在**首选项**对话框中，在**选择可见列**下选择要显示的列。

默认情况下，此模式显示**名称**、**类型**、**状态**、**资源**和**之后开始**列。

### **表格视图** – 筛选结果
<a name="table-view-filter-results"></a>

通过应用一个或多个基于属性（如**状态**）或日期和时间范围的筛选条件，来限制显示的信息量。例如，要查看执行失败的步骤，请应用以下筛选条件：

1. 选择**按属性筛选或按关键词搜索**，然后在**属性**下选择**状态**。

1. 在**运算符**下，选择**状态 =**。

1. 选择**状态 = Failed**。

1. （可选）选择**清除筛选条件**，移除已应用的筛选条件。

### **事件视图** – 筛选结果
<a name="event-view-filter-results"></a>

通过应用一个或多个基于属性（如**类型**）或日期和时间范围的筛选条件，来限制显示的信息量。例如，要查看执行失败的 `Task` 状态步骤，请应用以下筛选条件：

1. 选择**按属性筛选或按关键词搜索**，然后在**属性**下选择**类型**。

1. 在**运算符**下，选择**类型 =**。

1. 选择**类型 = TaskFailed**。

1. （可选）选择**清除筛选条件**，移除已应用的筛选条件。

### **事件视图** – 检查 **TaskFailed** 事件详细信息
<a name="event-view-inspect-failed-task-details"></a>

选择 **TaskFailed** 事件 ID 旁边的箭头图标来检查其详细信息，包括输入、输出和资源调用，这些信息显示在下拉框中。