솔루션 - AWS Flow Framework Java용

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

솔루션

다음 솔루션을 사용하여 이전 버전과 호환되지 않는 변경을 방지할 수 있습니다. 자세한 내용은 결정자 코드 변경예제 시나리오 단원을 참조하십시오.

버전 관리 사용

이 솔루션에서는 결정자를 새 클래스에 복사하고 결정자를 수정한 다음, 새 워크플로 버전에서 결정자를 등록합니다.

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 버전에 등록됩니다. 그러나 마이그레이션 후 새 실행은 true로 설정된 입력 데이터의 skipSecondTimer 필드로 시작합니다.

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(); } }

프로그램을 실행하면 모든 실행이 성공적으로 완료됩니다.