工作流程實作 - AWS Flow Framework 對於爪哇

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

工作流程實作

若要實作工作流程,您可以撰寫可實作所需 @Workflow 界面的類別。例如,可以如下述實作範例工作流程界面 (MyWorkflow):

public class MyWFImpl implements MyWorkflow { MyActivitiesClient client = new MyActivitiesClientImpl(); @Override public void startMyWF(int a, String b){ Promise<Integer> result = client.activity1(); client.activity2(result); } @Override public void signal1(int a, int b, String c){ //Process signal client.activity2(a + b); } }

此類別中的 @Execute 方法是工作流程邏輯的進入點。因為框架使用回覆來重新建構處理決策任務時的物件狀態,所以會為每個決策任務建立新的物件。

@Workflow 界面的 @Execute 方法中,不允許使用 Promise<T> 做為參數。這麼做的原因是進行非同步呼叫純粹是發起人的決策。工作流程實作本身不是取決於呼叫是同步還是非同步。因此,產生的用戶端界面具有採用 Promise<T> 參數的多載,以非同步呼叫這些方法。

@Execute 方法的傳回類型只能是 voidPromise<T>。請注意,對應外部用戶端的傳回類型是 void,而不是 Promise<>。因為外部用戶端不是要透過非同步程式碼使用,所以外部用戶端未傳回 Promise 物件。若要取得外部説明之工作流程執行的結果,您可以設計工作流程,以透過活動來更新外部資料存放區中的狀態。Amazon SWF 的可見性 API 也可用於檢索工作流程結果以進行診斷。不建議您使用可見度 API 來取回工作流程執行結果做為一般實務,因為可能會調節這些 API 呼叫。可見度 API 需要您使用 WorkflowExecution 結構來識別工作流程執行。您可以呼叫 getWorkflowExecution 方法,以從產生的工作流程用戶端取得此結構。此方法會傳回 WorkflowExecution 結構,其對應至用戶端所繫結的工作流程執行。請參Amazon Simple Workflow Service API 參考,以獲取可見度 API 的詳細資訊。

從工作流程實作呼叫活動時,您應該使用產生的活動用戶端。同樣地,若要傳送訊號,請使用產生的工作流程用戶端。

決策內容

只要框架執行工作流程程式碼,框架就會提供環境內容。此內容提供可在工作流程實作 (例如建立計時器) 中存取的內容專屬功能。如需詳細資訊,請參閱「執行內容」小節。

公開執行狀態

Amazon SWF 可讓您在工作流程歷史記錄中新增自訂狀態。會透過對 Amazon SWF 服務的可見度呼叫以及 Amazon SWF 主控台,將工作流程執行所報告的最新狀態傳回給您。例如,在訂單處理工作流程中,您可以報告不同階段的訂單狀態,例如「收到訂單」、「送出訂單」等等。在 中AWS Flow Framework,這是透過已標註釋之工作流程界面上的方法完成,該方法已標註釋之@GetState註釋。決策者完成決策任務的處理時,就會呼叫此方法以從工作流程實作取得最新狀態。除了可見度呼叫之外,也可以使用產生的外部用戶端 (在內部使用可見度 API 呼叫) 來擷取狀態。

下列範例示範如何設定執行內容。

@Workflow @WorkflowRegistrationOptions(defaultExecutionStartToCloseTimeoutSeconds = 60, defaultTaskStartToCloseTimeoutSeconds = 10) public interface PeriodicWorkflow { @Execute(version = "1.0") void periodicWorkflow(); @GetState String getState(); } @Activities(version = "1.0") @ActivityRegistrationOptions(defaultTaskScheduleToStartTimeoutSeconds = 300, defaultTaskStartToCloseTimeoutSeconds = 3600) public interface PeriodicActivity { void activity1(); } public class PeriodicWorkflowImpl implements PeriodicWorkflow { private DecisionContextProvider contextProvider = new DecisionContextProviderImpl(); private WorkflowClock clock = contextProvider.getDecisionContext().getWorkflowClock(); private PeriodicActivityClient activityClient = new PeriodicActivityClientImpl(); private String state; @Override public void periodicWorkflow() { state = "Just Started"; callPeriodicActivity(0); } @Asynchronous private void callPeriodicActivity(int count, Promise<?>... waitFor) { if(count == 100) { state = "Finished Processing"; return; } // call activity activityClient.activity1(); // Repeat the activity after 1 hour. Promise<Void> timer = clock.createTimer(3600); state = "Waiting for timer to fire. Count = "+count; callPeriodicActivity(count+1, timer); } @Override public String getState() { return state; } } public class PeriodicActivityImpl implements PeriodicActivity { @Override public static void activity1() { ... } }

隨時可以使用產生的外部用戶端來擷取工作流程執行的最新狀態。

PeriodicWorkflowClientExternal client = new PeriodicWorkflowClientExternalFactoryImpl().getClient(); System.out.println(client.getState());

在上述範例中,會報告各種階段的執行狀態。工作流程執行個體啟動時,periodicWorkflow 會將初始狀態報告為「剛啟動」('Just Started')。每個 callPeriodicActivity 呼叫接著都會更新工作流程狀態。呼叫 activity1 100 次之後,會傳回方法,並完成工作流程執行個體。

工作流程區域變數

您有時可能需要在工作流程實作中使用靜態變數。例如,您可能想要在工作流程實作中,存放能從多種位置 (類別可能不同) 存取的計數器。不過,您無法依賴工作流程中的靜態變數,原因是靜態變數是在多個執行緒之間共享,而這會發生問題,因為工作者可能會同時處理不同執行緒上的不同決策任務。或者,您可以將這類狀態存放在工作流程實作的欄位中,但您接著需要傳遞實作物件。為了解決此需求,框架會提供 WorkflowExecutionLocal<?> 類別。任何需要具有靜態變數 (例如語意) 的狀態都應該使用 WorkflowExecutionLocal<?> 保持為執行個體區域變數。您可以宣告和使用這類型的靜態變數。例如,在下列程式碼片段中,WorkflowExecutionLocal<String> 會用以存放使用者名稱。

public class MyWFImpl implements MyWF { public static WorkflowExecutionLocal<String> username = new WorkflowExecutionLocal<String>(); @Override public void start(String username){ this.username.set(username); Processor p = new Processor(); p.updateLastLogin(); p.greetUser(); } public static WorkflowExecutionLocal<String> getUsername() { return username; } public static void setUsername(WorkflowExecutionLocal<String> username) { MyWFImpl.username = username; } } public class Processor { void updateLastLogin(){ UserActivitiesClient c = new UserActivitiesClientImpl(); c.refreshLastLogin(MyWFImpl.getUsername().get()); } void greetUser(){ GreetingActivitiesClient c = new GreetingActivitiesClientImpl(); c.greetUser(MyWFImpl.getUsername().get()); } }