

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# Amazon SWF でのディサイダーの開発
<a name="swf-dg-dev-deciders"></a>

ディサイダーとは、ワークフロー実行中に実行されるワークフロータイプの調整ロジックの実装です。単一のワークフロータイプに複数のディサイダーを実行できます。

ワークフロー実行の実行状態はワークフロー履歴に保存されるため、ディサイダーはステートレスにできます。Amazon SWF はワークフロー実行履歴を維持し、それを各決定タスクを持つディサイダーに提供します。これにより、必要に応じて動的にディサイダーの追加や削除ができ、ワークフローの処理が大変スケーラブルになります。システム負荷の増加に合わせて、増加した容量を処理するためにディサイダーをさらに追加するだけです。ただし、特定のワークフロー実行に対して、いつでも決定タスクは 1 つしかオープンにできないことに注意してください。

ワークフロー実行に状態変更が発生するたびに、Amazon SWF は決定タスクをスケジュールします。ディサイダーは、決定タスクを受信するたびに以下を行います。
+ 決定タスクを提供されたワークフロー実行履歴を解釈します。
+ ワークフロー実行履歴に基づいて調整ロジックを適用し、次に実行すべきことを決定します。各決定は決定構造によって表されます。
+ 決定タスクを完了し、Amazon SWF に決定のリストを提供します。

このセクションではディサイダーを開発する方法を説明しますが、それには以下の点が含まれます。
+ 決定タスクをポーリングするためのディサイダーのプログラミング
+ ワークフロー実行履歴を解釈し決定を行うためのディサイダーのプログラミング
+ 決定タスクに応答するためのディサイダーのプログラミング

このセクションの例では、e コマースのサンプルワークフローにディサイダーをプログラムする方法を示します。

ディサイダーは、サービス API を通して Amazon SWF と通信できれば、任意の言語で実装でき、どこででも実行できます。

**Topics**
+ [調整ロジックの定義](#swf-dg-coordination-logic)
+ [決定タスクのポーリング](#swf-dg-polling-decision-tasks)
+ [調整ロジックの適用](#swf-dg-apply-coord-logic)
+ [決定の応答](#swf-dg-responding-with-decisions)
+ [ワークフロー実行のクローズ](#swf-dg-closing-workflows)
+ [ディサイダーの起動](#swf-dg-deciders-launch)

## 調整ロジックの定義
<a name="swf-dg-coordination-logic"></a>

ディサイダーの開発時にまず行うのは、調整ロジックを定義することです。e コマースの例では、前のアクティビティの完了後に各アクティビティをスケジュールする調整ロジックは、以下のようになります。

```
IF lastEvent = "StartWorkflowInstance"
 addToDecisions ScheduleVerifyOrderActivity

ELSIF lastEvent = "CompleteVerifyOrderActivity"
 addToDecisions ScheduleChargeCreditCardActivity

ELSIF lastEvent = "CompleteChargeCreditCardActivity"
 addToDecisions ScheduleCompleteShipOrderActivity

ELSIF lastEvent = "CompleteShipOrderActivity"
 addToDecisions ScheduleRecordOrderCompletion

ELSIF lastEvent = "CompleteRecordOrderCompletion"
 addToDecisions CloseWorkflow

ENDIF
```

ディサイダーはワークフロー実行履歴に調整ロジックを適用し、`RespondDecisionTaskCompleted` アクションを使用して決定タスクを完了するときに決定のリストを作成します。

## 決定タスクのポーリング
<a name="swf-dg-polling-decision-tasks"></a>

各ディサイダーは、決定タスクをポーリングします。決定タスクには、アクティビティタスクのスケジューリングのような決定を生成するのにディサイダーが使用する情報が含まれます。決定タスクをポーリングするには、ディサイダーは `PollForDecisionTask` アクションを使用します。

この例では、ディサイダーは `customerOrderWorkflow-0.1` TaskList を指定して決定タスクをポーリングします。

```
https://swf.us-east-1.amazonaws.com
PollForDecisionTask
{
  "domain": "867530901",
  "taskList": {"name": "customerOrderWorkflow-v0.1"},
  "identity": "Decider01",
  "maximumPageSize": 50,
  "reverseOrder": true
}
```

指定したタスクリストの決定タスクは、利用可能な場合は Amazon SWF により即時返されます。利用可能な決定タスクがない場合、Amazon SWF は接続を最大 60 秒間保持し、利用可能になり次第タスクを返します。タスクが利用可能にならない場合、Amazon SWF は空の応答を返します。空の応答とは、`taskToken` の値が空の文字列になっている `Task` 構造です。空の応答を受信した場合は、必ず別のタスクをポーリングするようディサイダーをプログラムしてください。

決定タスクが利用可能な場合、Amazon SWF が返す応答には、その決定タスクとワークフロー実行履歴のページ分割された表示が含まれます。

この例では、最新のイベントのタイプがワークフロー実行の開始を示し、入力要素には最初のタスクを実行するのに必要な情報が含まれています。

```
{
  "events": [
    {
      "decisionTaskStartedEventAttributes": {
        "identity": "Decider01",
        "scheduledEventId": 2
      },
      "eventId": 3,
      "eventTimestamp": 1326593394.566,
      "eventType": "DecisionTaskStarted"
    }, {
      "decisionTaskScheduledEventAttributes": {
        "startToCloseTimeout": "600",
        "taskList": { "name": "specialTaskList" }
      },
      "eventId": 2,
      "eventTimestamp": 1326592619.474,
      "eventType": "DecisionTaskScheduled"
    }, {
      "eventId": 1,
      "eventTimestamp": 1326592619.474,
      "eventType": "WorkflowExecutionStarted",
      "workflowExecutionStartedEventAttributes": {
        "childPolicy" : "TERMINATE",
        "executionStartToCloseTimeout" : "3600",
        "input" : "data-used-decider-for-first-task",
        "parentInitiatedEventId": 0,
        "tagList" : ["music purchase", "digital", "ricoh-the-dog"],
        "taskList": { "name": "specialTaskList" },
        "taskStartToCloseTimeout": "600",
        "workflowType": {
          "name": "customerOrderWorkflow",
          "version": "1.0"
        }
      }
    }
  ],
  ...
}
```

ワークフロー実行履歴を受信したら、ディサイダーは履歴を解釈して調整ロジックに基づいて決定を行います。

単一のワークフロー実行のワークフロー履歴のイベント数が大きい場合があるので、返される結果は複数ページに分割される可能性があります。後続ページを取得するには、最初の呼び出しで返された *nextPageToken* を使用して `PollForDecisionTask` を追加で呼び出します。この *nextPageToken* を使用して `GetWorkflowExecutionHistory` を*呼び出さない*ことに注意してください。代わりに、再度 `PollForDecisionTask` を呼び出します。

## 調整ロジックの適用
<a name="swf-dg-apply-coord-logic"></a>

ディサイダーが決定タスクを受信したら、これまで何が起きたかを判断するためワークフロー実行履歴を解釈するようプログラムします。これに基づいて、決定のリストを生成する必要があります。

e コマースの例では、ワークフロー履歴の最後のイベントにのみ関心があるので、次のロジックを定義します。

```
IF lastEvent = "StartWorkflowInstance"
 addToDecisions ScheduleVerifyOrderActivity

ELSIF lastEvent = "CompleteVerifyOrderActivity"
 addToDecisions ScheduleChargeCreditCardActivity

ELSIF lastEvent = "CompleteChargeCreditCardActivity"
 addToDecisions ScheduleCompleteShipOrderActivity

ELSIF lastEvent = "CompleteShipOrderActivity"
 addToDecisions ScheduleRecordOrderCompletion

ELSIF lastEvent = "CompleteRecordOrderCompletion"
 addToDecisions CloseWorkflow

ENDIF
```

lastEvent が `CompleteVerifyOrderActivity` の場合、`ScheduleChargeCreditCardActivity` アクティビティを決定のリストに加えます。

ディサイダーは、行うべき決定を判断すると Amazon SWF に適切な決定で応答できます。

## 決定の応答
<a name="swf-dg-responding-with-decisions"></a>

ワークフロー履歴を解釈して決定のリストを生成したら、ディサイダーはそれらの決定を Amazon SWF に返すことができる状態にあります。

ワークフロー実行履歴から必要なデータを抽出し、次にワークフローの次の適切なアクションを指定する決定を作成するようディサイダーをプログラムします。ディサイダーはこれらの決定を `RespondDecisionTaskCompleted` アクションを使用して Amazon SWF に返します。利用可能な[決定タイプ](https://docs.aws.amazon.com/amazonswf/latest/apireference/API_Decision.html)のリストについては、「*Amazon Simple Workflow Service API Reference*」(Amazon Simple Workflow Service API リファレンス) を参照してください。

e コマースの例では、ディサイダーが生成した一連の決定を返すときに、ワークフロー実行履歴にあるクレジットカード入力も含めます。その結果アクティビティワーカーは、アクティビティタスクを実行するのに必要なすべての情報を持つことになります。

ワークフロー実行のすべてのアクティビティが完了すると、ディサイダーはワークフロー実行をクローズします。

```
https://swf.us-east-1.amazonaws.com
RespondDecisionTaskCompleted
{
  "taskToken" : "12342e17-80f6-FAKE-TASK-TOKEN32f0223",
  "decisions" : [
    {
      "decisionType" :"ScheduleActivityTask",
      "scheduleActivityTaskDecisionAttributes" : {
        "control" :"OPTIONAL_DATA_FOR_DECIDER",
        "activityType" : {
          "name" :"ScheduleChargeCreditCardActivity",
          "version" :"1.1"
        },
        "activityId" :"3e2e6e55-e7c4-beef-feed-aa815722b7be",
        "scheduleToCloseTimeout" :"360",
        "taskList" : { "name" :"CC_TASKS" },
        "scheduleToStartTimeout" :"60",
        "startToCloseTimeout" :"300",
        "heartbeatTimeout" :"60",
        "input" : "4321-0001-0002-1234: 0212 : 234"
      }
    }
  ]
}
```

## ワークフロー実行のクローズ
<a name="swf-dg-closing-workflows"></a>

ビジネスプロセスが完了している、つまりこれ以上実行するアクティビティがないと判断すると、ディサイダーはワークフロー実行をクローズする決定を生成します。

ワークフロー実行をクローズするには、ワークフロー履歴のイベントを解釈してこれまで何が起きたかを判断し、ワークフロー実行をクローズすべきか確認するようディサイダーをプログラムします。

ワークフローが正常に完了した場合、`CompleteWorkflowExecution` 決定で `RespondDecisionTaskCompleted` を呼び出すことでワークフロー実行をクローズします。または、`FailWorkflowExecution` 決定を使用して誤った実行を失敗させることができます。

e コマースの例では、ディサイダーは履歴を確認し、調整ロジックに基づいてワークフロー実行をクローズする決定を決定のリストに追加して、クローズワークフロー決定で `RespondDecisionTaskCompleted` アクションを開始します。

**注記**  
ワークフロー実行のクローズが失敗するケースがあります。たとえば、ディサイダーがワークフロー実行をクローズしている間にシグナルを受信すると、そのクローズ決定は失敗します。この可能性に対処するには、ディサイダーが確実に決定タスクをポーリングし続けるようにします。また、次の決定タスクを受信するディサイダーが、実行のクローズを妨げたイベント (このケースではシグナル) に確実に対応するようにします。

ワークフロー実行のキャンセルをサポートする可能性もあります。これは、特に実行時間が長いワークフローの場合に便利なことがあります。キャンセルをサポートするには、ディサイダーは履歴の `WorkflowExecutionCancelRequested` イベントを処理する必要があります。このイベントは、実行のキャンセルがリクエストされたことを示します。ディサイダーは、たとえば実行中のアクティビティタスクをキャンセルしたり `CancelWorkflowExecution` 決定で `RespondDecisionTaskCompleted` アクションを呼び出してワークフローをクローズするといった、適切なクリーンアップアクションを実行する必要があります。

以下の例では、`RespondDecisionTaskCompleted` を呼び出して現在のワークフロー実行をキャンセルするよう指定します。

```
https://swf.us-east-1.amazonaws.com
RespondDecisionTaskCompleted
{
  "taskToken" : "12342e17-80f6-FAKE-TASK-TOKEN32f0223",
  "decisions" : [
    {
      "decisionType":"CancelWorkflowExecution",
      "CancelWorkflowExecutionAttributes":{
        "Details": "Customer canceled order"
      }
    }
  ]
}
```

Amazon SWF は、ワークフロー実行のクローズやキャンセルの決定が確実にディサイダーが送信する最後の決定であるかを確認します。つまり、ワークフローをクローズする決定の後にも決定がある一連の決定を持つことは無効です。

## ディサイダーの起動
<a name="swf-dg-deciders-launch"></a>

ディサイダー開発が完了したら、1 つ以上のディサイダーを起動することができます。

ディサイダーを起動するには、ディサイダープラットフォームで使用できる実行可能ファイルに調整ロジックをパッケージ化します。たとえば、Linux コンピュータと Windows コンピュータの両方で実行できる Java 実行可能ファイルとしてディサイダーコードをパッケージ化します。

起動すると、ディサイダーはタスクを求めて Amazon SWF のポーリングを開始するはずです。ワークフロー実行が開始され Amazon SWF が決定タスクをスケジュールするまで、これらのポーリングはタイムアウトして空の応答を取得します。空の応答とは、`taskToken` の値が空の文字列になっている `Task` 構造です。ディサイダーは単にポーリングし続けます。

Amazon SWF は、いつでもワークフロー実行に対して 1 つの決定タスクのみがアクティブになれるようにします。これにより、競合する決定といった問題を回避できます。さらに、Amazon SWF は実行中のディサイダーの数に関係なく単一の決定タスクが単一のディサイダーに割り当てられるようにします。

ディサイダーが別の決定タスクを処理中に決定タスクを生成する何かが発生すると、Amazon SWF は現在のタスクが完了するまでその新しいタスクをキューに入れます。現在のタスクが完了した後、Amazon SWF は新しい決定タスクを使用可能にします。また、ディサイダーが決定タスクを処理している間に複数のアクティビティーが完了した場合、Amazon SWF は複数のタスク完了を考慮して 1 つの新しい決定タスクしか作成しないという意味で、決定タスクを一括処理します。ただし、各タスク完了は、ワークフロー実行履歴で個々のイベントを受け取ります。

ポーリングはアウトバウンドリクエストであるため、ディサイダーは、Amazon SWF エンドポイントにアクセスできるすべてのネットワークで実行できます。

ワークフロー実行が進行するには、1 つ以上のディサイダーが実行中である必要があります。ディサイダーは必要な数だけ起動できます。Amazon SWF は同じタスクリストでポーリングする複数のディサイダーをサポートします。