

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

# HelloWorldWorkflowAsync 應用程式
<a name="getting-started-example-helloworldworkflowasync"></a>

在某些時候會偏好讓工作流程在本機執行某些任務，而不是使用活動。不過，工作流程任務通常包含處理 `Promise<T>` 物件所代表的值。如果您將 `Promise<T>` 物件傳遞給同步工作流程方法，則會立即執行方法，但無法存取 `Promise<T>` 物件值，直到物件就緒為止。您可以輪詢 `Promise<T>.isReady`，直到傳回 `true` 為止，但此效率較顯不彰，而且方法可能會被阻擋很長一段時間。較佳的方式是使用「非同步方法」**。

非同步方法的實作方式與標準方法非常類似，通常是工作流程實作類別的成員，並且會在工作流程實作的內容中執行。套用 `@Asynchronous` 註釋 (其指示框架將之視為活動)，您即可將之指定為非同步方法。
+ 工作流程實作呼叫非同步方法時，會立即予以傳回。非同步方法一般會傳回 `Promise<T>` 物件，而此物件會在方法完成時就緒。
+ 如果您將一或多個 `Promise<T>` 物件傳遞給非同步方法，則會延遲執行，直到所有輸入物件都就緒為止。因此，非同步方法可以存取其輸入 `Promise<T>` 值，而不會發出例外狀況。

**注意**  
由於 AWS Flow Framework 適用於 Java 的 執行工作流程的方式，非同步方法通常會執行多次，因此您應該只將它們用於快速的低額外負荷任務。您應該使用活動來執行大型運算這類冗長任務。如需詳細資訊，請參閱[AWS Flow Framework 基本概念：分散式執行](awsflow-basics-distributed-execution.md)。

本主題是 HelloWorldWorkflowAsync (為 HelloWorldWorkflow 的修改版本，將其中一個活動取代為非同步方法) 的演練。若要實作應用程式，請在您的專案目錄中建立 helloWorld.HelloWorldWorkflow 套件的副本，並命名為 helloWorld.HelloWorldWorkflowAsync。

**注意**  
本主題是建置在 [HelloWorld 應用程式](getting-started-example-helloworld.md)​ 和 [HelloWorldWorkflow 應用程式](getting-started-example-helloworldworkflow.md)​ 主題所呈現的概念和檔案。熟悉這些主題呈現的檔案和概念再繼續。

下列各節說明如何修改原始 HelloWorldWorkflow 程式碼以使用非同步方法。

## HelloWorldWorkflowAsync 活動實作
<a name="getting-started-example-helloworldworkflowasync.activities"></a>

HelloWorldWorkflowAsync 會在 `GreeterActivities` 中實作其活動工作者界面，如下所示：

```
import com.amazonaws.services.simpleworkflow.flow.annotations.Activities;
import com.amazonaws.services.simpleworkflow.flow.annotations.ActivityRegistrationOptions;

@Activities(version="2.0")
@ActivityRegistrationOptions(defaultTaskScheduleToStartTimeoutSeconds = 300,
                             defaultTaskStartToCloseTimeoutSeconds = 10)
public interface GreeterActivities {
   public String getName();
   public void say(String what);
}
```

此界面與 HelloWorldWorkflow 所使用的界面類似，相異之處如下：
+ 此界面會省略 `getGreeting` 活動；非同步方法現在會處理該任務。
+ 版本編號設定為 2.0。向 Amazon SWF 註冊活動界面之後，除非您變更版本號碼，否則無法修改它。

其餘的活動方法實作與 HelloWorldWorkflow 相同。只需要從 `GreeterActivitiesImpl` 中刪除 `getGreeting`。

## HelloWorldWorkflowAsync 工作流程實作
<a name="getting-started-example-helloworldworkflowasync.workflow"></a>

HelloWorldWorkflowAsync 定義工作流程界面，如下所示：

```
import com.amazonaws.services.simpleworkflow.flow.annotations.Execute;
import com.amazonaws.services.simpleworkflow.flow.annotations.Workflow;
import com.amazonaws.services.simpleworkflow.flow.annotations.WorkflowRegistrationOptions;

@Workflow
@WorkflowRegistrationOptions(defaultExecutionStartToCloseTimeoutSeconds = 3600)
public interface GreeterWorkflow {

   @Execute(version = "2.0")
   public void greet();
}
```

除了新的版本編號之外，界面會與 HelloWorldWorkflow 相同。與活動相同，如果您想要變更已註冊的工作流程，則必須變更其版本。

HelloWorldWorkflowAsync 實作工作流程，如下所示：

```
import com.amazonaws.services.simpleworkflow.flow.annotations.Asynchronous;
import com.amazonaws.services.simpleworkflow.flow.core.Promise;

public class GreeterWorkflowImpl implements GreeterWorkflow {
   private GreeterActivitiesClient operations = new GreeterActivitiesClientImpl();

   @Override
   public void greet() {
      Promise<String> name = operations.getName();
      Promise<String> greeting = getGreeting(name);
      operations.say(greeting);
   }

   @Asynchronous
   private Promise<String> getGreeting(Promise<String> name) {
      String returnString = "Hello " + name.get() + "!";
      return Promise.asPromise(returnString);
   }
}
```

HelloWorldWorkflowAsync 會將 `getGreeting` 活動取代為 `getGreeting` 非同步方法，但 `greet` 方法的運作方式極為相同：

1. 執行 `getName` 活動，其會立即傳回代表名稱的 `Promise<String>` 物件 `name`。

1. 呼叫 `getGreeting` 非同步方法，並將 `name` 物件遞給它。`getGreeting` 會立即傳回代表問候語的 `Promise<String>` 物件 `greeting`。

1. 執行 `say` 活動，並將 `greeting` 物件傳遞給它。

1. `getName` 完成時，`name` 會就緒，且 `getGreeting` 會使用其值來建構問候語。

1. `getGreeting` 完成時，`greeting` 會就緒，且 `say` 會將字串列印至主控台。

差異在於以問候語呼叫非同步 `getGreeting` 方法，而不是呼叫活動用戶端來執行 `getGreeting` 活動。最後的結果會相同，但 `getGreeting` 方法的運作方式與 `getGreeting` 活動有些不同。
+ 工作流程工作者會使用標準函數呼叫語意來執行 `getGreeting`。不過，活動的非同步執行是由 Amazon SWF 媒介。
+ `getGreeting` 會在工作流程實作程序中執行。
+ `getGreeting` 會傳回 `Promise<String>` 物件，而不是 `String` 物件。若要取得 `Promise` 保留的 String 值，您可以呼叫其 `get()` 方法。不過，由於活動是以非同步方式執行，其傳回值可能不會立即就緒； `get()`將引發例外狀況，直到非同步方法的傳回值可用為止。

  如需 `Promise` 運作方式的詳細資訊，請參閱「[AWS Flow Framework 基本概念：活動與工作流程之間的資料交換](awsflow-basics-data-exchange-activities-workflows.md)」。

`getGreeting` 透過將問候語字串傳遞給靜態 `Promise.asPromise` 方法，來建立傳回值。此方法會建立適當類型的 `Promise<T>` 物件，並設定值，然後讓使之進入就緒狀態。

## HelloWorldWorkflowAsync 工作流程和活動主機與啟動者
<a name="getting-started-example-helloworldworkflowasync.host"></a>

HelloWorldWorkflowAsync 將 `GreeterWorker` 實作為工作流程和活動實作的主機類別。此實作與 HelloWorldWorkflow 實作相同，差別在於 `taskListToPoll` 的名稱設為 "`HelloWorldAsyncList`"。

```
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient;
import com.amazonaws.services.simpleworkflow.flow.ActivityWorker;
import com.amazonaws.services.simpleworkflow.flow.WorkflowWorker;

public class GreeterWorker {
    public static void main(String[] args) throws Exception {
        ClientConfiguration config = new ClientConfiguration().withSocketTimeout(70*1000);

        String swfAccessId = System.getenv("AWS_ACCESS_KEY_ID");
        String swfSecretKey = System.getenv("AWS_SECRET_KEY");
        AWSCredentials awsCredentials = new BasicAWSCredentials(swfAccessId, swfSecretKey);

        AmazonSimpleWorkflow service = new AmazonSimpleWorkflowClient(awsCredentials, config);
        service.setEndpoint("https://swf.us-east-1.amazonaws.com");

        String domain = "helloWorldWalkthrough";
        String taskListToPoll = "HelloWorldAsyncList";

        ActivityWorker aw = new ActivityWorker(service, domain, taskListToPoll);
        aw.addActivitiesImplementation(new GreeterActivitiesImpl());
        aw.start();

        WorkflowWorker wfw = new WorkflowWorker(service, domain, taskListToPoll);
        wfw.addWorkflowImplementationType(GreeterWorkflowImpl.class);
        wfw.start();
    }
}
```

HelloWorldWorkflowAsync 會在 `GreeterMain` 中實作工作流程啟動者；與 HelloWorldWorkflow 實作相同。

若要執行工作流程，請執行 `GreeterWorker` 和 `GreeterMain`，如同 HelloWorldWorkflow。