Cenário de exemplo - AWS Flow Framework para Java

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Cenário de exemplo

Há uma classe de alterações de código consideradas como incompatíveis com versões anteriores. Essas alterações incluem atualizações que modificam o número, o tipo ou a ordem das tarefas programadas. Considere o seguinte exemplo:

Você escreve o código do agente de decisão para programar duas tarefas com temporizador. Você inicia uma execução e executa uma decisão. Como resultado, as duas tarefas com temporizador são programadas, com os IDs 1 e 2.

Se você atualizar o código do agente de decisão para programar apenas um temporizador antes da próxima decisão ser executada, durante a próxima tarefa de decisão a estrutura não reproduzirá o segundo evento TimerFired, porque o ID 2 não corresponde a nenhuma tarefa com temporizador produzida pelo código.

Esboço do cenário

O esboço a seguir mostra as etapas deste cenário. O objetivo final do cenário é migrar para um sistema que programa apenas um temporizador mas não provoca falhas em execuções iniciadas antes da migração.

  1. A versão inicial do agente de decisão

    1. Escrever o agente de decisão.

    2. Iniciar o agente de decisão.

    3. O agente de decisão programa dois temporizadores.

    4. O agente de decisão inicia cinco execuções.

    5. Interromper o agente de decisão.

  2. Uma alteração no agente de decisão incompatível com versões anteriores

    1. Modificar o agente de decisão.

    2. Iniciar o agente de decisão.

    3. O agente de decisão programa um temporizador.

    4. O agente de decisão inicia cinco execuções.

As seções a seguir incluem exemplos de código Java que mostram como implementar esse cenário. Os exemplos de código da seção Soluções mostram várias maneiras de como corrigir alterações incompatíveis com versões anteriores.

nota

Você pode usar a versão mais recente do AWS SDK for Java para executar esse código.

Código comum

O código Java a seguir não é alterado entre os exemplos desse cenário.

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

Como escrever o código inicial do agente de decisão

O seguinte é o código Java inicial do agente de decisão. Ele está registrado como a versão 1 e programa duas tarefas com temporizador de cinco segundos.

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

Simulação de uma alteração incompatível com versões anteriores

O código Java do agente de decisão a seguir é um bom exemplo de uma alteração incompatível com versões anteriores. O código ainda está registrado como a versão 1, mas programa apenas um temporizador.

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

O código Java a seguir permite que você simule o problema de alterações incompatíveis com versões anteriores executando o agente de decisão modificado.

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

Quando você executa o programa, as três execuções que falham são as que começaram na versão inicial do agente de decisão e continuaram depois da migração.