

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

# 了解 AWS Flow Framework 適用於 Java 的 中的任務
<a name="details"></a>

**Topics**
+ [任務](#details.task)
+ [執行順序](#details.order)
+ [工作流程執行](#details.workflow)
+ [不確定性](#details.non)

## 任務
<a name="details.task"></a>

 AWS Flow Framework 適用於 Java 的 用來管理非同步程式碼執行的基礎基本概念是 `Task`類別。`Task` 類型的物件代表必須同步執行的工作。當您呼叫同步方法時，框架會建立 `Task` 以在該方法中執行程式碼，並將它置入清單供稍後執行。同樣地，當您呼叫 `Activity` 時，也會為它建立 `Task`。方法呼叫會在這之後傳回，通常傳回 `Promise<T>` 做為呼叫的未來結果。

`Task` 類別為公有，可直接使用。例如，我們可以重新撰寫 Hello World 範例，讓其使用 `Task`，而不使用同步方法。

```
@Override
public void startHelloWorld(){
       final Promise<String> greeting = client.getName();
        new Task(greeting) {
        @Override
        protected void doExecute() throws Throwable {
        	client.printGreeting("Hello " + greeting.get() +"!");
        }
    };
}
```

當傳遞到 `Task` 建構函數的所有 `Promise` 都準備就緒時，框架會呼叫 `doExecute()` 方法。如需 `Task`類別的詳細資訊，請參閱 適用於 Java 的 AWS SDK 文件。

框架也包含稱為 `Functor` 的類別，它代表也是 `Promise<T>` 的 `Task`。`Functor` 物件會在 `Task` 完成時準備就緒。在下列範例中，會建立 `Functor` 以取得歡迎訊息：

```
Promise<String> greeting = new Functor<String>() {
    @Override
    protected Promise<String> doExecute() throws Throwable {
        return client.getGreeting();
    }
};
client.printGreeting(greeting);
```

## 執行順序
<a name="details.order"></a>

只有當傳遞到對應之同步方法或活動的所有 `Promise<T>` 具類型參數都準備就緒時，任務才符合執行資格。隨時可供執行的 `Task` 在邏輯上已移至就緒佇列。換言之，它已排程準備執行。工作者類別會透過叫用您在非同步方法內文中撰寫的程式碼，或在活動方法的情況下，透過在 Amazon Simple Workflow Service (AWS) 中排程活動任務來執行任務。

在任務執行並產生結果時，它們會讓其他任務準備就緒，讓程式持續執行不中斷。框架執行任務的方式對了解您同步程式碼的執行順序很重要。在您的程式中循序出現的程式碼，實際上不一定按照此順序執行。

```
Promise<String> name = getUserName();
printHelloName(name);
printHelloWorld();
System.out.println("Hello, Amazon!");

@Asynchronous
private Promise<String> getUserName(){
	return Promise.asPromise("Bob");
}
@Asynchronous
private void printHelloName(Promise<String> name){
	System.out.println("Hello, " + name.get() + "!");
}
@Asynchronous
private void printHelloWorld(){
	System.out.println("Hello, World!");
}
```

上列程式碼列印如下：

```
Hello, Amazon!
Hello, World!
Hello, Bob
```

這可能不是您期望的內容，但仔細思考同步方法的任務是如何執行的，就很容易說明：

1. 呼叫 `getUserName` 建立 `Task`。我們稱它為 `Task1`。由於 `getUserName`不會使用任何參數，因此 `Task1` 會立即放入就緒佇列中。

1. 接著，呼叫 `printHelloName` 建立需要等候 `getUserName` 結果的 `Task`。我們稱它為 `Task2`。由於必要值尚未就緒， `Task2` 會放入等待清單中。

1. 然後建立` printHelloWorld` 任務，並新增至就緒佇列。我們稱它為 `Task3`。

1. 然後，陳述`println`式會列印「Hello， Amazon！」 主控台。

1. 此時，`Task1` 和 `Task3` 會在就緒佇列中，而 `Task2` 則在等候清單中。

1. 工作者執行 `Task1`，其結果讓 `Task2` 準備就緒。`Task2` 會新增至 `Task3` 後面的就緒佇列。

1. `Task3` 和 `Task2` 接著依此順序執行。

活動依相同的模式執行。當您在活動用戶端上呼叫 方法時，它會建立 ，`Task`在執行時排程 Amazon SWF 中的活動。

框架依賴注入邏輯的程式碼產生及動態代理等功能，將方法呼叫轉換成您程式的活動呼叫及同步任務。

## 工作流程執行
<a name="details.workflow"></a>

工作流程實作的執行也由工作者類別管理。當您在工作流程用戶端上呼叫方法時，它會呼叫 Amazon SWF 來建立工作流程執行個體。Amazon SWF 中的任務不應與架構中的任務混淆。Amazon SWF 中的任務是活動任務或決策任務。執行活動任務很簡單。活動工作者類別會從 Amazon SWF 接收活動任務、在您的實作中叫用適當的活動方法，並將結果傳回給 Amazon SWF。

決策任務的執行較為複雜。工作流程工作者會從 Amazon SWF 接收決策任務。決策任務實際上是一項請求，詢問工作流程邏輯接下來要做什麼。第一個決策任務是針對工作流程執行個體透過工作流程用戶端啟動時而產生。一旦收到此決策任務，框架即會開始在以 `@Execute` 標註的工作流程方法中執行程式碼。此方法會執行排程活動的協調性邏輯。當工作流程執行個體的狀態變更時，例如，當活動完成時，進一步排定決策任務。此時，工作流程邏輯可以根據活動的結果決定執行動作，例如，它可能決定排程另一項活動。

框架將決策任務順暢轉譯為工作流程邏輯，對開發人員隱藏所有這些細節。就開發人員的觀點而言，此程式碼看起來就像是一般的程式。在涵蓋範圍內，框架會使用 Amazon SWF 維護的歷史記錄將其映射至 Amazon SWF 的呼叫和決策任務。當決策任務到達時，框架會重新執行外掛在目前已完成活動結果中的程式。解鎖等候這些結果的同步方法和活動並繼續執行程式。

執行的範例影像處理工作流程和對應的歷史記錄會顯示在下表中。


**執行縮圖工作流程**  

| 執行工作流程程式 | Amazon SWF 維護的歷史記錄  | 
| --- | --- | 
| 初始執行 | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/amazonswf/latest/awsflowguide/details.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/amazonswf/latest/awsflowguide/details.html)  | 
| 重新播放 | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/amazonswf/latest/awsflowguide/details.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/amazonswf/latest/awsflowguide/details.html)  | 
| 重新播放 | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/amazonswf/latest/awsflowguide/details.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/amazonswf/latest/awsflowguide/details.html)  | 
| 重新播放 | 
|  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/amazonswf/latest/awsflowguide/details.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/amazonswf/latest/awsflowguide/details.html)  | 

呼叫 `processImage` 時，架構會在 Amazon SWF 中建立新的工作流程執行個體。這是正在啟動之工作流程執行個體的永久記錄。程式會執行直到呼叫`downloadImage`活動為止，這會要求 Amazon SWF 排程活動。工作流程會進一步執行並建立後續活動的任務，但在`downloadImage`活動完成之前都無法執行；因此，此重播階段會結束。Amazon SWF 會為執行`downloadImage`活動分派任務，一旦完成，就會在歷史記錄中記錄結果。工作流程現在已準備好繼續進行，而決策任務是由 Amazon SWF 產生。框架收到決策任務，並重新執行外掛在歷史記錄所記錄之下載影像結果中的工作流程。這會解除封鎖 的任務`createThumbnail`，並透過在 Amazon SWF 中排程`createThumbnail`活動任務來更進一步地執行程式。`uploadImage` 會重複同樣的程序。程式以此方式繼續執行，直到工作流程處理完所有影像且無任何等待中的任務為止。由於本機不會儲存任何執行狀態，因此每個決策任務都可能在不同機器上執行。這可讓您輕鬆撰寫可容錯且可擴展的程式。

## 不確定性
<a name="details.non"></a>

由於架構依賴於重播，因此協調程式碼 （活動實作除外的所有工作流程程式碼） 必須具有決定性。例如，您程式中的控制流程不應該相依於亂數或目前的時間。由於這些物件會在叫用之間變更，因此重播可能不會遵循協同運作邏輯的相同路徑。這會導致未預期的結果或錯誤。框架提供 `WorkflowClock` 讓您以確定方式來取得目前的時間。如需詳細資訊，請參閱「[執行內容](executioncontext.md)」一節。

**注意**  
工作流程實作物件的不正確 Spring 接線也會導致不確定性。工作流程實作 Bean 及其相依的 Bean 都必須在工作流程範圍內 (`WorkflowScope`)。例如，將工作流程實作 Bean 接線到保留狀態且位於全域內容中的 Bean，將會導致未預期的行為。如需詳細資訊，請參閱 [Spring 整合](test.md#test.spring) 區段内容。