解決方案 - AWS Flow Framework 對於爪哇

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

解決方案

您可以使用下列解決方案來避免回溯不相容變更。如需詳細資訊,請參閱「變更決策者程式碼」和「範例藍本」。

使用版本控制

在此解決方案中,您可以將決策者複製至新類別,並修改決策者,然後在新的工作流程版本下註冊決策者。

VersionedDecider.java

package sample.v2; import com.amazonaws.services.simpleworkflow.flow.DecisionContext; import com.amazonaws.services.simpleworkflow.flow.DecisionContextProviderImpl; import com.amazonaws.services.simpleworkflow.flow.WorkflowClock; import com.amazonaws.services.simpleworkflow.flow.annotations.Execute; import com.amazonaws.services.simpleworkflow.flow.annotations.Workflow; import com.amazonaws.services.simpleworkflow.flow.annotations.WorkflowRegistrationOptions; import sample.Input; @Workflow @WorkflowRegistrationOptions(defaultExecutionStartToCloseTimeoutSeconds = 60, defaultTaskStartToCloseTimeoutSeconds = 5) public interface Foo { @Execute(version = "2") public void sample(Input input); public static class Impl implements Foo { private DecisionContext decisionContext = new DecisionContextProviderImpl().getDecisionContext(); private WorkflowClock clock = decisionContext.getWorkflowClock(); @Override public void sample(Input input) { System.out.println("Decision (V2) WorkflowId: " + decisionContext.getWorkflowContext().getWorkflowExecution().getWorkflowId()); clock.createTimer(5); } } }

在更新過的 Java 程式碼中,第二個決策者工作者會同時執行兩個版本的工作流程,讓進行中的執行得以單獨繼續,無關乎第 2 版中的變更。

RunVersionedDecider.java

package sample; import com.amazonaws.services.simpleworkflow.flow.WorkflowWorker; public class VersionedChange extends SampleBase { public static void main(String[] args) throws Exception { new VersionedChange().run(); } public void run() throws Exception { // Start the first version of the decider, with workflow version 1 WorkflowWorker before = new WorkflowWorker(service, domain, taskList); before.addWorkflowImplementationType(sample.v1.Foo.Impl.class); before.start(); // Start a few executions with version 1 startFiveExecutions("Foo.sample", "1", new Input()); // Stop the first decider worker and wait a few seconds // for its pending pollers to match and return before.suspendPolling(); sleep(2000); // At this point, three executions are still open, with more decisions to make // Start a worker with both the previous version of the decider (workflow version 1) // and the modified code (workflow version 2) WorkflowWorker after = new WorkflowWorker(service, domain, taskList); after.addWorkflowImplementationType(sample.v1.Foo.Impl.class); after.addWorkflowImplementationType(sample.v2.Foo.Impl.class); after.start(); // Start a few more executions with version 2 startFiveExecutions("Foo.sample", "2", new Input()); printExecutionResults(); } }

當您執行程式時,所有執行會順利完成。

使用功能標記

回溯相容性問題的另一種解決方案是分支處理程式碼,以支援根據輸入資料 (而非工作流程版本) 來分支處理相同類別中的兩個實作。

當您採取這種方法時,可以在每次引進敏感變更時將欄位新增至輸入物件 (或修改輸入物件的現有欄位)。針對在遷移之前啟動的執行,輸入物件不會有欄位 (或有不同值)。因此,您不需要增加版本編號。

注意

如果您新增欄位,則請確定 JSON 還原序列化程序具有回溯相容。引進欄位之前序列化的物件仍然應該在遷移之後成功還原序列化。因為 JSON 只要欄位遺漏就會設定 null 值,所以一律會使用已封箱的類型 (Boolean,而非 boolean),並處理值為 null 的情況。

FeatureFlagDecider.java

package sample.v1.featureflag; import com.amazonaws.services.simpleworkflow.flow.DecisionContext; import com.amazonaws.services.simpleworkflow.flow.DecisionContextProviderImpl; import com.amazonaws.services.simpleworkflow.flow.WorkflowClock; import com.amazonaws.services.simpleworkflow.flow.annotations.Execute; import com.amazonaws.services.simpleworkflow.flow.annotations.Workflow; import com.amazonaws.services.simpleworkflow.flow.annotations.WorkflowRegistrationOptions; import sample.Input; @Workflow @WorkflowRegistrationOptions(defaultExecutionStartToCloseTimeoutSeconds = 60, defaultTaskStartToCloseTimeoutSeconds = 5) public interface Foo { @Execute(version = "1") public void sample(Input input); public static class Impl implements Foo { private DecisionContext decisionContext = new DecisionContextProviderImpl().getDecisionContext(); private WorkflowClock clock = decisionContext.getWorkflowClock(); @Override public void sample(Input input) { System.out.println("Decision (V1 feature flag) WorkflowId: " + decisionContext.getWorkflowContext().getWorkflowExecution().getWorkflowId()); clock.createTimer(5); if (!input.getSkipSecondTimer()) { clock.createTimer(5); } } } }

在更新過的 Java 程式碼中,仍然會針對第 1 版註冊兩個工作流程版本的程式碼。不過,在遷移之後,會啟動輸入資料的 skipSecondTimer 欄位設為 true 的新執行。

RunFeatureFlagDecider.java

package sample; import com.amazonaws.services.simpleworkflow.flow.WorkflowWorker; public class FeatureFlagChange extends SampleBase { public static void main(String[] args) throws Exception { new FeatureFlagChange().run(); } public void run() throws Exception { // Start the first version of the decider WorkflowWorker before = new WorkflowWorker(service, domain, taskList); before.addWorkflowImplementationType(sample.v1.Foo.Impl.class); before.start(); // Start a few executions startFiveExecutions("Foo.sample", "1", new Input()); // Stop the first decider worker and wait a few seconds // for its pending pollers to match and return before.suspendPolling(); sleep(2000); // At this point, three executions are still open, with more decisions to make // Start a new version of the decider that introduces a change // while preserving backwards compatibility based on input fields WorkflowWorker after = new WorkflowWorker(service, domain, taskList); after.addWorkflowImplementationType(sample.v1.featureflag.Foo.Impl.class); after.start(); // Start a few more executions and enable the new feature through the input data startFiveExecutions("Foo.sample", "1", new Input().setSkipSecondTimer(true)); printExecutionResults(); } }

當您執行程式時,所有執行會順利完成。