本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
工作流程實作
若要實作工作流程,您可以撰寫可實作所需 @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
方法的傳回類型只能是 void
或 Promise<
。請注意,對應外部用戶端的傳回類型是 T
>void
,而不是 Promise<>
。由於外部用戶端不適用於非同步程式碼,因此外部用戶端不會傳回Promise
物件。若要取得外部陳述的工作流程執行結果,您可以設計工作流程,透過 活動更新外部資料存放區中的狀態。Amazon SWF 的可見APIs 也可用於擷取工作流程結果以進行診斷。不建議您使用可見性 APIs 擷取工作流程執行的結果作為一般實務,因為 Amazon SWF 可能會調節這些 API 呼叫。可見度 API 需要您使用 WorkflowExecution
結構來識別工作流程執行。您可以呼叫 getWorkflowExecution
方法,以從產生的工作流程用戶端取得此結構。此方法會傳回 WorkflowExecution
結構,其對應至用戶端所繫結的工作流程執行。如需可見性 API 的詳細資訊,請參閱 Amazon Simple Workflow Service API 參考。 APIs
從工作流程實作呼叫活動時,您應該使用產生的活動用戶端。同樣地,若要傳送訊號,請使用產生的工作流程用戶端。
決策內容
只要框架執行工作流程程式碼,框架就會提供環境內容。此內容提供可在工作流程實作 (例如建立計時器) 中存取的內容專屬功能。如需詳細資訊,請參閱「執行內容」小節。
公開執行狀態
Amazon SWF 可讓您在工作流程歷史記錄中新增自訂狀態。工作流程執行報告的最新狀態會透過對 Amazon SWF 服務和 Amazon SWF 主控台的可見性呼叫傳回給您。例如,在訂單處理工作流程中,您可以報告不同階段的訂單狀態,例如「收到訂單」、「送出訂單」等等。在 AWS Flow Framework 適用於 Java 的 中,這會透過工作流程界面上標註註釋的方法來完成@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()); } }