Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.
Beispielszenario
Es gibt eine Klasse von Codeänderungen, die als abwärtsinkompatibel gilt. Zu diesen Änderungen gehören Aktualisierungen, bei denen die Anzahl, der Typ oder die Reihenfolge der geplanten Aufgaben verändert werden. Betrachten Sie das folgende Beispiel:
Sie schreiben Entscheidercode, um zwei Timer-Aufgaben zu planen. Sie beginnen mit der Ausführung und führen eine Entscheidung aus. Daraufhin werden zwei Timer-Aufgaben mit den IDs 1
und 2
geplant.
Wenn Sie den Entscheidercode so aktualisieren, dass nur ein Timer geplant wird, bevor die nächste Entscheidung ausgeführt wird, kann das Framework bei der nächsten Entscheidungsaufgabe das zweite TimerFired
-Ereignis nicht wiedergeben, da die ID 2
nicht mit einer Timer-Aufgabe übereinstimmt, die vom Code erzeugt wurde.
Überblick über das Szenario
Der folgende Überblick zeigt die einzelnen Schritte dieses Szenarios. Endziel des Szenarios ist es, eine Migration auf ein System durchzuführen, bei dem nur ein Timer geplant wird, ohne dass dies dazu führt, dass Ausführungen fehlschlagen, die vor der Migration gestartet wurden.
-
Die erste Entscheiderversion
-
Schreiben Sie den Entscheider.
-
Starten Sie den Entscheider.
-
Der Entscheider plant zwei Timer.
-
Der Entscheider startet fünf Ausführungen.
-
Halten Sie den Entscheider an.
-
-
Eine abwärtsinkompatible Änderung am Entscheider
-
Ändern Sie den Entscheider.
-
Starten Sie den Entscheider.
-
Der Entscheider plant einen Timer.
-
Der Entscheider startet fünf Ausführungen.
-
Die folgenden Abschnitte enthalten Java-Beispielcode, mit dem sich dieses Szenario implementieren lässt. Die Codebeispiele im Abschnitt Lösungen zeigen zwei Möglichkeiten, abwärtsinkompatible Änderungen zu beheben.
Anmerkung
Sie können die aktuelle Version von AWS SDK for Java
Gängiger Code
Der folgende Java-Code ändert sich zwischen den Beispielen in diesem Szenario nicht.
SampleBase.java
package sample; import java.util.ArrayList; import java.util.List; import java.util.UUID; import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow; import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClientBuilder; import com.amazonaws.services.simpleworkflow.flow.JsonDataConverter; import com.amazonaws.services.simpleworkflow.model.DescribeWorkflowExecutionRequest; import com.amazonaws.services.simpleworkflow.model.DomainAlreadyExistsException; import com.amazonaws.services.simpleworkflow.model.RegisterDomainRequest; import com.amazonaws.services.simpleworkflow.model.Run; import com.amazonaws.services.simpleworkflow.model.StartWorkflowExecutionRequest; import com.amazonaws.services.simpleworkflow.model.TaskList; import com.amazonaws.services.simpleworkflow.model.WorkflowExecution; import com.amazonaws.services.simpleworkflow.model.WorkflowExecutionDetail; import com.amazonaws.services.simpleworkflow.model.WorkflowType; public class SampleBase { protected String domain = "DeciderChangeSample"; protected String taskList = "DeciderChangeSample-" + UUID.randomUUID().toString(); protected AmazonSimpleWorkflow service = AmazonSimpleWorkflowClientBuilder.defaultClient(); { try { AmazonSimpleWorkflowClientBuilder.defaultClient().registerDomain(new RegisterDomainRequest().withName(domain).withDescription("desc").withWorkflowExecutionRetentionPeriodInDays("7")); } catch (DomainAlreadyExistsException e) { } } protected List<WorkflowExecution> workflowExecutions = new ArrayList<>(); protected void startFiveExecutions(String workflow, String version, Object input) { for (int i = 0; i < 5; i++) { String id = UUID.randomUUID().toString(); Run startWorkflowExecution = service.startWorkflowExecution( new StartWorkflowExecutionRequest().withDomain(domain).withTaskList(new TaskList().withName(taskList)).withInput(new JsonDataConverter().toData(new Object[] { input })).withWorkflowId(id).withWorkflowType(new WorkflowType().withName(workflow).withVersion(version))); workflowExecutions.add(new WorkflowExecution().withWorkflowId(id).withRunId(startWorkflowExecution.getRunId())); sleep(1000); } } protected void printExecutionResults() { waitForExecutionsToClose(); System.out.println("\nResults:"); for (WorkflowExecution wid : workflowExecutions) { WorkflowExecutionDetail details = service.describeWorkflowExecution(new DescribeWorkflowExecutionRequest().withDomain(domain).withExecution(wid)); System.out.println(wid.getWorkflowId() + " " + details.getExecutionInfo().getCloseStatus()); } } protected void waitForExecutionsToClose() { loop: while (true) { for (WorkflowExecution wid : workflowExecutions) { WorkflowExecutionDetail details = service.describeWorkflowExecution(new DescribeWorkflowExecutionRequest().withDomain(domain).withExecution(wid)); if ("OPEN".equals(details.getExecutionInfo().getExecutionStatus())) { sleep(1000); continue loop; } } return; } } protected void sleep(int millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }
Input.java
package sample; public class Input { private Boolean skipSecondTimer; public Input() { } public Input(Boolean skipSecondTimer) { this.skipSecondTimer = skipSecondTimer; } public Boolean getSkipSecondTimer() { return skipSecondTimer != null && skipSecondTimer; } public Input setSkipSecondTimer(Boolean skipSecondTimer) { this.skipSecondTimer = skipSecondTimer; return this; } }
Schreiben des ersten Entscheidercodes
Nachfolgend sehen Sie den ersten Java-Code des Entscheiders. Er ist als Version 1
registriert und plant zwei fünfsekündige Timer-Aufgaben.
InitialDecider.java
package sample.v1; 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) WorkflowId: " + decisionContext.getWorkflowContext().getWorkflowExecution().getWorkflowId()); clock.createTimer(5); clock.createTimer(5); } } }
Simulieren einer abwärtsinkompatiblen Änderung
Der folgende, modifizierte Java-Code des Entscheiders ist ein gutes Beispiel für eine abwärtsinkompatible Änderung. Der Code ist weiterhin als Version 1
registriert, plant jedoch nur noch einen Timer.
ModifiedDecider.java
package sample.v1.modified; 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 modified) WorkflowId: " + decisionContext.getWorkflowContext().getWorkflowExecution().getWorkflowId()); clock.createTimer(5); } } }
Mit dem folgenden Java-Code können Sie das Problem einer abwärtsinkompatiblen Änderung simulieren, indem Sie den modifizierten Entscheider ausführen.
RunModifiedDecider.java
package sample; import com.amazonaws.services.simpleworkflow.flow.WorkflowWorker; public class BadChange extends SampleBase { public static void main(String[] args) throws Exception { new BadChange().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 the modified version of the decider WorkflowWorker after = new WorkflowWorker(service, domain, taskList); after.addWorkflowImplementationType(sample.v1.modified.Foo.Impl.class); after.start(); // Start a few more executions startFiveExecutions("Foo.sample", "1", new Input()); printExecutionResults(); } }
Wenn Sie das Programm ausführen, scheitern die drei Ausführungen, die mit der ersten Version des Entscheiders gestartet und nach der Migration fortgesetzt wurden.