Soluções - 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á.

Soluções

Você pode usar as seguintes soluções para evitar alterações incompatíveis com versões anteriores. Para obter mais informações, consulte Como fazer alterações no código do agente de decisão e Cenário de exemplo.

Usar versionamento

Nesta solução, você copia o agente de decisão em uma classe nova, modifica o agente de decisão e o registra em uma versão nova do fluxo de trabalho.

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

No código Java atualizado, o segundo operador de agente de decisão executa as duas versões do fluxo de trabalho permitindo que as execuções em andamento continuem a ser executadas independentemente da alterações na versão 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(); } }

Quando você executa o programa, todas as execuções são concluídas com êxito.

Uso de sinalizadores de recursos

Outra solução de problemas de compatibilidade com versões anteriores é ramificar o código para oferecer suporte a duas implementações na mesma classe com base nos dados de entrada e não nas versões do fluxo de trabalho.

Ao usar essa abordagem, você adiciona campos (ou modifica os campos existentes) a seus objetos de entrada sempre que introduz alterações importantes. Em execuções iniciadas antes da migração, o objeto de entrada não terá o campo (ou terá um valor diferente). Portanto, você não precisa aumentar o número da versão.

nota

Se você adicionar novos campos, verifique se o processo de desserialização do JSON é compatível com versões anteriores. Os objetos serializados antes da introdução do campo ainda devem ser desserializados com êxito após a migração. Como o JSON define um valor null sempre que um campo está ausente, use sempre tipos demarcados (Boolean em vez de boolean) e trate dos casos em que o valor é 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); } } } }

No código Java atualizado, o código das duas versões do fluxo de trabalho ainda está registrado para a versão 1. No entanto, após a migração, as novas execuções são iniciadas com o campo skipSecondTimer dos dados de entrada definido como 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(); } }

Quando você executa o programa, todas as execuções são concluídas com êxito.