

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# Step Functions 的最佳實務
<a name="sfn-best-practices"></a>

**管理狀態和轉換資料**  
了解如何[使用變數在狀態與使用 JSONata 轉換資料之間傳遞資料](workflow-variables.md)。 [ JSONata](transforming-data.md)

下列主題是最佳實務，可協助您管理和最佳化 Step Functions 工作流程。

**Topics**
+ [使用快速工作流程最佳化成本](#cost-opt-exp-workflows)
+ [在 Step Functions 中標記狀態機器和活動](#concepts-tagging)
+ [使用逾時以避免停滯的 Step Functions 工作流程執行](#sfn-stuck-execution)
+ [在 Step Functions 中使用 Amazon S3 ARNs 而非傳遞大型承載](#avoid-exec-failures)
+ [開始新的執行，以避免達到 Step Functions 中的歷史記錄配額](#bp-history-limit)
+ [處理暫時性 Lambda 服務例外狀況](#bp-lambda-serviceexception)
+ [避免輪詢活動任務時的延遲](#bp-activity-pollers)
+ [避免 CloudWatch 資源政策大小限制](#bp-cwl)

## 使用快速工作流程最佳化成本
<a name="cost-opt-exp-workflows"></a>

Step Functions 會根據您用來建置狀態機器的工作流程類型，決定標準和快速工作流程的定價。若要最佳化無伺服器工作流程的成本，您可以遵循下列其中一項或兩項建議：

如需選擇標準或快速工作流程類型如何影響帳單的資訊，請參閱 [AWS Step Functions定價](https://aws.amazon.com/step-functions/pricing/)。

### 標準工作流程中的巢狀 Express 工作流程
<a name="cost-opt-exp-wflow-nesting"></a>

Step Functions 會執行具有有限持續時間和步驟數量的工作流程。有些工作流程可能會在短時間內完成執行。其他可能需要結合長時間執行和high-event-rate的工作流程。使用 Step Functions，您可以從多個更小、更簡單的工作流程中建置大型、複雜的工作流程。

例如，若要建置訂單處理工作流程，您可以將所有非等冪動作納入標準工作流程。這可能包括動作，例如透過人工互動核准訂單和處理付款。然後，您可以在 Express 工作流程中結合一系列等冪動作，例如傳送付款通知和更新產品庫存。您可以在標準工作流程中將此 Express 工作流程巢狀化。在此範例中，標準工作流程稱為*父系狀態機器*。巢狀 Express 工作流程稱為*子狀態機器*。

### 將標準工作流程遷移至 Express 工作流程
<a name="cost-opt-exp-wflow-conversion"></a>

如果標準工作流程符合下列要求，您應該考慮將它們遷移至 Express 工作流程：
+ 您的工作流程必須在五分鐘內完成執行。
+ 您的工作流程符合*at-least-once*執行模型，這表示工作流程中的每個步驟可能會執行一次以上。
+ 您的工作流程**不使用** `.waitForTaskToken`或服務`.sync`整合模式。

**重要**  
快速工作流程使用 Amazon CloudWatch Logs 記錄執行歷史記錄。使用 CloudWatch Logs 時會產生額外費用。

**使用主控台將標準工作流程遷移至 Express 工作流程**

1. 開啟 [Step Functions 主控台](https://console.aws.amazon.com/states/home?region=us-east-1#/)。

1. 在**狀態機器**頁面上，選擇要開啟的標準類型狀態機器。
**提示**  
從**任何類型**下拉式清單中，選擇**標準**以篩選狀態機器清單，並僅檢視標準工作流程。

1. 選擇**複製到新的**。

   Workflow Studio 會在[設計模式](workflow-studio.md#wfs-interface-design-mode)顯示您所選狀態機器的工作流程時開啟。

1. （選用） 更新工作流程設計。

1. 為您的狀態機器指定名稱。若要這樣做，請選擇 **MyStateMachine** 預設狀態機器名稱旁的編輯圖示。然後，在**狀態機器組態**中，在**狀態機器名稱方塊中指定名稱**。

1. （選用） 在**狀態機器組態**中，指定其他工作流程設定，例如狀態機器類型及其執行角色。

   請確定針對**類型**，您選擇 **Express**。在**狀態機器設定**上保留所有其他預設選擇。
**注意**  
如果您要遷移先前在 [AWS CDK](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-stepfunctions-readme.html)或 中定義的標準工作流程AWS SAM，則必須變更 `Type`和 `Resource` 名稱的值。

1. 在**確認角色建立**對話方塊中，選擇**確認**以繼續。

   您也可以選擇**檢視角色設定**以返回**狀態機器組態**。
**注意**  
如果您刪除 Step Functions 建立的 IAM 角色，Step Functions 稍後無法重新建立該角色。同樣地，如果您修改角色 （例如，從 IAM 政策中的主體移除 Step Functions)，Step Functions 稍後無法還原其原始設定。

如需管理工作流程的成本最佳化時最佳實務和指導方針的詳細資訊，請參閱[建置符合成本效益的AWS Step Functions工作流程](https://aws.amazon.com/blogs/compute/building-cost-effective-aws-step-functions-workflows/)。

## 在 Step Functions 中標記狀態機器和活動
<a name="concepts-tagging"></a>

AWS Step Functions支援標記狀態機器 （標準和快速） 和活動。標籤可協助您追蹤和管理 資源，並在 AWS Identity and Access Management(IAM) 政策中提供更好的安全性。標記 Step Functions 資源之後，您可以使用 來管理它們AWS Resource Groups。若要了解如何操作，請參閱 [AWS Resource Groups使用者指南](https://docs.aws.amazon.com/ARG/latest/userguide/)。

對於標籤型授權，如下列範例所示的狀態機器執行資源會繼承與狀態機器相關聯的標籤。

```
arn:{{partition}}:states:{{region}}:{{account-id}}:execution:{{<StateMachineName>:<ExecutionId>}}
```

當您呼叫 [DescribeExecution](https://docs.aws.amazon.com/step-functions/latest/apireference/API_DescribeExecution.html) 或指定執行資源 ARN 的其他 APIs 時，Step Functions 會使用與狀態機器相關聯的標籤，在執行標籤型授權時接受或拒絕請求。這可協助您允許或拒絕存取狀態機器層級的狀態機器執行。

若要查看資源標記的相關限制，請參閱 [標記的相關限制](service-quotas.md#sfn-limits-tagging)。

### 進行標記以分配成本
<a name="tagging-cost"></a>

您可以使用成本分配標籤來識別狀態機器的用途，並在AWS帳單中反映該組織。註冊以取得AWS您的帳戶帳單，以包含標籤索引鍵和值。如需[設定報告的詳細資訊，請參閱《 使用者指南》中的設定每月成本分配](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/configurecostallocreport.html#allocation-report)報告。 *AWS Billing*

例如，您可以新增代表您的成本中心和 Step Functions 資源用途的標籤，如下所示。



- **`StateMachine1`**
  - **金鑰:** Cost Center / **值:** 34567
  - **金鑰:** Application / **值:** Image processing

- **`StateMachine2`**
  - **金鑰:** Cost Center / **值:** 34567
  - **金鑰:** Application / **值:** Rekognition processing



### 針對安全進行標記
<a name="tagging-security"></a>

IAM 支援根據標籤控制對 資源的存取。若要根據標籤控制存取，請在 IAM 政策的條件元素中提供資源標籤的相關資訊。

例如，您可以限制對所有 Step Functions 資源的存取，其中包含索引鍵為 `environment`且值為 的標籤`production`。

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Deny",
            "Action": [
                "states:TagResource",
                "states:DeleteActivity",
                "states:DeleteStateMachine",
                "states:StopExecution"
            ],
            "Resource": "*",
            "Condition": {
                "StringEquals": {"aws:ResourceTag/environment": "production"}
            }
        }
    ]
}
```

如需詳細資訊，請參閱《IAM 使用者指南》中的「[使用標籤控制存取](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_tags.html)」。

### 在 Step Functions 主控台中管理標籤
<a name="tagging-console"></a>

您可以在 Step Functions 主控台中檢視和管理狀態機器的標籤。從狀態機器的 **Details (詳細資訊)** 頁面，選擇 **Tags (標籤)**。

### 使用 Step Functions API 動作管理標籤
<a name="tagging-api"></a>

若要使用 Step Functions API 管理標籤，請使用下列 API 動作：
+ [https://docs.aws.amazon.com/step-functions/latest/apireference/API_ListTagsForResource.html](https://docs.aws.amazon.com/step-functions/latest/apireference/API_ListTagsForResource.html)
+ [https://docs.aws.amazon.com/step-functions/latest/apireference/API_TagResource.html](https://docs.aws.amazon.com/step-functions/latest/apireference/API_TagResource.html)
+ [https://docs.aws.amazon.com/step-functions/latest/apireference/API_UntagResource.html](https://docs.aws.amazon.com/step-functions/latest/apireference/API_UntagResource.html)

## 使用逾時以避免停滯的 Step Functions 工作流程執行
<a name="sfn-stuck-execution"></a>

根據預設，Amazon States Language 不會為狀態機器定義指定逾時。如果沒有明確的逾時，Step Functions 通常僅倚賴活動工作者的回應來知道任務已完成。如果發生錯誤，且 `TimeoutSeconds` 欄位未指定 `Activity`或 `Task` 狀態，則執行會卡在等待永遠不會出現的回應。

若要避免這種情況，請在狀態機器`Task`中建立 時指定合理的逾時。例如：

```
"ActivityState": {
  "Type": "Task",
  "Resource": "arn:aws:states:{{region}}:{{account-id}}:activity:HelloWorld",
  "TimeoutSeconds": 300,
  "Next": "NextState"
}
```

如果您使用[具有任務字符 (.waitForTaskToken) 的回呼](connect-to-resource.md#connect-wait-token)，建議您使用活動訊號並在`Task`狀態定義中新增 `HeartbeatSeconds` 欄位。您可以`HeartbeatSeconds`設定 小於任務逾時，因此，如果您的工作流程失敗並出現活動訊號錯誤，則您知道這是由於任務失敗，而不是任務需要很長時間才能完成。

```
{
  "StartAt": "Push to SQS",
  "States": {
    "Push to SQS": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sqs:sendMessage.waitForTaskToken",
      "HeartbeatSeconds": 600,
      "Parameters": {
        "MessageBody": { "myTaskToken.$": "$$.Task.Token" },
        "QueueUrl": "https://sqs.us-east-1.amazonaws.com/{{account-id}}/push-based-queue"
      },
      "ResultPath": "$.SQS",
      "End": true
    }
  }
}
```

如需詳細資訊，請參閱 Amazon States Language 文件[任務工作流程狀態](state-task.md)中的 。

**注意**  
您可以使用 Amazon States Language 定義中的 `TimeoutSeconds` 欄位來設定狀態機器的逾時。如需詳細資訊，請參閱[Step Functions 工作流程的 Amazon States Language 狀態機器結構](statemachine-structure.md)。

## 在 Step Functions 中使用 Amazon S3 ARNs 而非傳遞大型承載
<a name="avoid-exec-failures"></a>

在狀態之間傳遞大型資料承載的執行作業可能會被終止。如果您要在狀態之間傳遞的資料可能超過 256 KiB，請使用 Amazon Simple Storage Service (Amazon S3) 來存放資料，並在 `Payload` 參數中剖析儲存貯體的 Amazon Resource Name (ARN)，以取得儲存貯體名稱和金鑰值。或者，調整您的實作，以便在您的執行作業中傳遞較小的承載。

在下列範例中，狀態機器會將輸入傳遞至 AWS Lambda函數，該函數會處理 Amazon S3 儲存貯體中的 JSON 檔案。執行此狀態機器後，Lambda 函數會讀取 JSON 檔案的內容，並將檔案內容傳回為輸出。

**建立 Lambda 函式**  
下列名為 的 Lambda 函數會`{{pass-large-payload}}`讀取存放在特定 Amazon S3 儲存貯體中的 JSON 檔案的內容。

**注意**  
建立此 Lambda 函數之後，請務必為其 IAM 角色提供適當的許可，以便從 Amazon S3 儲存貯體讀取。例如，將 **AmazonS3ReadOnlyAccess** 許可連接到 Lambda 函數的角色。

```
import json
import boto3
import io
import os

s3 = boto3.client('s3')

def lambda_handler(event, context):
    event = event['Input']
    final_json = str()
    
    s3 = boto3.resource('s3')
    bucket = event['bucket'].split(':')[-1]
    filename = event['key']
    directory = "/tmp/{}".format(filename)
    
    s3.Bucket(bucket).download_file(filename, directory)
    
    with open(directory, "r") as jsonfile:
    
        final_json = json.load(jsonfile)
    
    os.popen("rm -rf /tmp")
    
    return final_json
```

**建立狀態機器**  
下列狀態機器會叫用您先前建立的 Lambda 函數。

```
{  
   "StartAt":"Invoke Lambda function",
   "States":{  
      "Invoke Lambda function":{  
         "Type":"Task",
         "Resource":"arn:aws:states:::lambda:invoke",
         "Parameters":{  
            "FunctionName":"arn:aws:lambda:us-east-2:123456789012:function:{{pass-large-payload}}",
            "Payload":{  
               "Input.$":"$"
            }
         },
         "OutputPath": "$.Payload",
         "End":true
      }
   }
}
```

您可以在 Amazon S3 儲存貯體中儲存該資料，並在 `Payload` 參數中傳遞儲存貯體的 Amazon Resource Name (ARN)，而不是在輸入中傳遞大量資料，以取得儲存貯體名稱和金鑰值。然後，您的 Lambda 函數可以使用該 ARN 直接存取資料。以下是狀態機器執行的範例輸入，其中資料存放在名為 的 Amazon S3 儲存貯`data.json`體中`{{amzn-s3-demo-large-payload-json}}`。

```
{
  "key": "data.json",
  "bucket": "{{arn:aws:s3:::amzn-s3-demo-large-payload-json}}"
}
```

## 開始新的執行，以避免達到 Step Functions 中的歷史記錄配額
<a name="bp-history-limit"></a>

AWS Step Functions執行事件歷史記錄中有 25，000 個項目的硬性配額。當執行達到 24，999 個事件時，它會等待下一個事件發生。
+ 如果事件編號 25，000 為 `ExecutionSucceeded`，則執行會成功完成。
+ 如果事件編號 25，000 不是 `ExecutionSucceeded`，則會記錄`ExecutionFailed`事件，且狀態機器執行會因為達到歷史記錄限制而失敗

若要避免針對長時間執行的執行達到此配額，您可以嘗試下列其中一個解決方法：
+ [在分散式模式中使用映射狀態](state-map-distributed.md)。在此模式中， `Map` 狀態會以子工作流程執行方式執行每個反覆運算，可實現高達 10，000 個平行子工作流程執行的高並行。每個子工作流程執行都有自己的獨立執行歷史記錄，與父工作流程的執行歷史記錄不同。
+ 直接從執行中`Task`執行的狀態啟動新的狀態機器執行。若要啟動此類巢狀工作流程執行，請在父系狀態機器中使用 Step Functions 的 `[StartExecution](https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartExecution.html)` API 動作以及必要的參數。如需使用巢狀工作流程的詳細資訊，請參閱 [從 Step Functions 中的任務狀態啟動工作流程執行](concepts-nested-workflows.md)或 [使用 Step Functions API 動作以繼續新的執行](tutorial-continue-new.md)教學課程。
**提示**  
若要部署範例巢狀工作流程，請參閱*AWS Step Functions研討會*中的[最佳化成本](https://catalog.workshops.aws/stepfunctions/nested-workflow)。
+ 實作使用 AWS Lambda函數的模式，該函數可以啟動狀態機器的新執行，以跨多個工作流程執行分割進行中的工作。如需詳細資訊，請參閱[使用 Lambda 函數在 Step Functions 中繼續新的執行](tutorial-use-lambda-cont-exec.md)教學課程。

## 處理暫時性 Lambda 服務例外狀況
<a name="bp-lambda-serviceexception"></a>

AWS Lambda偶爾可能會遇到暫時性服務錯誤。在此情況下，叫用 Lambda 會導致 500 錯誤，例如 `ClientExecutionTimeoutException`、`AWSLambdaException`、 `ServiceException`或 `SdkClientException`。最佳實務是在狀態機器中主動處理這些例外狀況，以`Retry`叫用 Lambda 函數或`Catch`錯誤。

Lambda 錯誤報告為 `Lambda.{{ErrorName}}`。若要重試 Lambda 服務例外狀況錯誤，您可以使用下列`Retry`程式碼。

```
"Retry": [ {
   "ErrorEquals": [ "Lambda.ClientExecutionTimeoutException", "Lambda.ServiceException", "Lambda.AWSLambdaException", "Lambda.SdkClientException"],
   "IntervalSeconds": 2,
   "MaxAttempts": 6,
   "BackoffRate": 2
} ]
```

**注意**  
Lambda 執行時間中未處理的錯誤歷史上僅報告為 `Lambda.Unknown`。在較新的執行時間中，逾時會在錯誤輸出`Sandbox.Timedout`中回報為 。  
當 Lambda 超過調用數量上限時，報告的錯誤將為 `Lambda.TooManyRequestsException`。  
在 `Lambda.Unknown`、 `Sandbox.Timedout`和 上進行比對`States.TaskFailed`，以處理可能的錯誤。您也可以使用 `States.ALL`，但必須是單獨且位於清單結尾。  
如需 Lambda `Handled`和`Unhandled`錯誤的詳細資訊，請參閱《 [AWS Lambda開發人員指南](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#API_Invoke_ResponseSyntax)`FunctionError`》中的 。

如需詳細資訊，請參閱下列內容：
+ [發生錯誤後重試](concepts-error-handling.md#error-handling-retrying-after-an-error)
+ [在 Step Functions 狀態機器中處理錯誤條件](tutorial-handling-error-conditions.md)
+ [Lambda 調用錯誤](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#API_Invoke_Errors)

## 避免輪詢活動任務時的延遲
<a name="bp-activity-pollers"></a>

`[GetActivityTask](https://docs.aws.amazon.com/step-functions/latest/apireference/API_GetActivityTask.html)` API 旨在提供[https://docs.aws.amazon.com/step-functions/latest/apireference/API_GetActivityTask.html#StepFunctions-GetActivityTask-response-taskToken](https://docs.aws.amazon.com/step-functions/latest/apireference/API_GetActivityTask.html#StepFunctions-GetActivityTask-response-taskToken)*恰好一次*的 。如果 `taskToken` 在與活動工作者通訊時遺失，可以封鎖數個 `GetActivityTask` 請求 60 秒來等待回應，直到 `GetActivityTask` 逾時為止。

如果您只有少量輪詢在等待回應，則所有請求可能都會排在封鎖的請求後面並且停止。不過，如果您為每個活動 Amazon Resource Name (ARN) 有大量未完成的輪詢，而且有部分請求在等待中停滯，則還有更多請求仍然可以取得 `taskToken` 並開始處理工作。

對於生產系統，我們建議每個活動 ARN 隨時至少都有 100 個開啟的輪詢。如果有一個輪詢遭到封鎖，而且有一部分的輪詢排在其後面，則有更多請求仍會收到 `GetActivityTask` 以在 `taskToken` 請求遭到封鎖時處理工作。

若要在輪詢任務時避免這幾種延遲問題：
+ 在您的活動工作者實作中，以個別的執行緒實作您的輪詢器。
+ 每個活動 ARN 隨時至少都有 100 個開啟的輪詢。
**注意**  
每個 ARN 擴展至 100 個開放輪詢可能所費不貲。例如，每個 ARN 100 個 Lambda 函數輪詢的成本是具有具有 100 個輪詢執行緒的單一 Lambda 函數的 100 倍。若要降低延遲*並*將成本降至最低，請使用具有非同步 I/O 的語言，然後針對每個工作人員實作多個輪詢執行緒。如需輪詢器執行緒與工作執行緒不同的範例活動工作者，請參閱 [範例：Ruby 中的活動工作者](concepts-activities.md#example-ruby-activity-worker)。

如需活動和活動工作者的詳細資訊，請參閱 [了解 Step Functions 中的活動](concepts-activities.md)。

## 避免 CloudWatch 資源政策大小限制
<a name="bp-cwl"></a>

當您使用記錄建立狀態機器，或更新現有狀態機器以啟用記錄時，Step Functions 必須使用您指定的日誌群組來更新 CloudWatch Logs 資源政策。CloudWatch Logs 資源政策限制為 5，120 個字元。

當 CloudWatch Logs 偵測到政策接近大小限制時，CloudWatch Logs 會自動啟用以 開頭的日誌群組記錄`/aws/vendedlogs/`。

您可以使用 為 CloudWatch Logs 日誌群組名稱加上字首`/aws/vendedlogs/`，以避免 CloudWatch Logs 資源政策大小限制。如果您在 Step Functions 主控台中建立日誌群組，建議的日誌群組名稱將會以 為字首`/aws/vendedlogs/states`。

CloudWatch Logs 在每個帳戶的每個區域也有十個資源政策的配額。如果您嘗試在帳戶中已有十個 CloudWatch Logs 資源政策的狀態機器上啟用記錄，將不會建立或更新狀態機器。如需記錄配額的詳細資訊，請參閱 [CloudWatch Logs 配額](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/cloudwatch_limits_cwl.html)。

如果您在將日誌傳送至 CloudWatch Logs 時遇到問題，請參閱 [Troubleshooting state machine logging to CloudWatch Logs](cw-logs.md#troubleshooting-logging-to-cloudwatch)。