Solusi - AWS Flow Framework untuk Java

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

Solusi

Anda dapat menggunakan solusi berikut untuk menghindari perubahan tidak sesuai ke belakang. Untuk informasi selengkapnya, lihat Membuat Perubahan pada Kode Decider dan Contoh skenario.

Menggunakan versioning

Dalam solusi ini, Anda menyalin decider ke kelas baru, memodifikasi decider, dan kemudian mendaftarkan decider di bawah versi alur kerja baru.

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

Dalam kode Java yang diperbarui, pekerja decider kedua menjalankan kedua versi alur kerja, memungkinkan eksekusi dalam penerbangan untuk terus mengeksekusi secara independen dari perubahan dalam versi 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(); } }

Ketika Anda menjalankan program, semua eksekusi berhasil diselesaikan.

Menggunakan Feature Flag

Solusi lain untuk masalah kompatibilitas mundur adalah kode cabang untuk mendukung dua implementasi di kelas yang sama adalah bercabang berdasarkan data input alih-alih versi alur kerja.

Ketika Anda mengambil pendekatan ini, Anda menambahkan bidang untuk (atau memodifikasi bidang yang ada) objek masukan Anda setiap kali Anda memperkenalkan perubahan yang sensitif. Untuk eksekusi yang dimulai sebelum migrasi, objek input tidak akan memiliki bidang (atau akan memiliki nilai yang berbeda). Dengan demikian, Anda tidak perlu menambah nomor versi.

catatan

Jika Anda menambahkan bidang baru, pastikan bahwa proses deserialization JSON kompatibel ke belakang. Objek yang diserialisasi sebelum pengenalan bidang harus tetap berhasil dideserialisasi setelah migrasi. Karena JSON menetapkan nilai null setiap kali bidang tidak ada, selalu gunakan tipe kotak (Boolean alih-alih boolean) dan tangani kasus di mana nilainya adalah 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); } } } }

Dalam kode Java yang diperbarui, kode untuk kedua versi alur kerja masih terdaftar untuk versi 1. Namun, setelah migrasi, eksekusi baru dimulai dengan bidang skipSecondTimer input data diatur ke 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(); } }

Ketika Anda menjalankan program, semua eksekusi berhasil diselesaikan.