From 2e74db86844f68f7d14b0a400c1478d648b15d82 Mon Sep 17 00:00:00 2001 From: Tom Hombergs Date: Sat, 24 Jul 2021 06:44:33 +1000 Subject: [PATCH 1/4] wip --- spring-boot/zero-downtime/pom.xml | 7 ++++ .../zerodowntime/CustomerController.java | 35 ++++++++++++++----- .../zerodowntime/CustomerRepository.java | 2 +- .../zerodowntime/FeatureFlagService.java | 24 +++++++++++++ .../LaunchDarklyConfiguration.java | 27 ++++++++++++++ .../zerodowntime/NewCustomer.java | 34 ++++++++++++++++++ .../zerodowntime/NewCustomerRepository.java | 6 ++++ .../{Customer.java => OldCustomer.java} | 6 ++-- .../src/main/resources/application.yml | 5 ++- .../migration/V002__add_address_columns.sql | 2 ++ 10 files changed, 134 insertions(+), 14 deletions(-) create mode 100644 spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/FeatureFlagService.java create mode 100644 spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/LaunchDarklyConfiguration.java create mode 100644 spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/NewCustomer.java create mode 100644 spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/NewCustomerRepository.java rename spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/{Customer.java => OldCustomer.java} (82%) create mode 100644 spring-boot/zero-downtime/src/main/resources/db/migration/V002__add_address_columns.sql diff --git a/spring-boot/zero-downtime/pom.xml b/spring-boot/zero-downtime/pom.xml index 55c678c..6c28e97 100644 --- a/spring-boot/zero-downtime/pom.xml +++ b/spring-boot/zero-downtime/pom.xml @@ -42,6 +42,13 @@ h2 + + + com.launchdarkly + launchdarkly-java-server-sdk + 5.3.0 + + diff --git a/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/CustomerController.java b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/CustomerController.java index 8da8a2b..550a356 100644 --- a/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/CustomerController.java +++ b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/CustomerController.java @@ -6,26 +6,43 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class CustomerController { - private final CustomerRepository customerRepository; + private final CustomerRepository oldCustomerRepository; + private final NewCustomerRepository newCustomerRepository; + private final FeatureFlagService featureFlagService; - public CustomerController(CustomerRepository customerRepository) { - this.customerRepository = customerRepository; + public CustomerController(CustomerRepository oldCustomerRepository, NewCustomerRepository newCustomerRepository, FeatureFlagService featureFlagService) { + this.oldCustomerRepository = oldCustomerRepository; + this.newCustomerRepository = newCustomerRepository; + this.featureFlagService = featureFlagService; } @GetMapping("/customers/create") String createUser() { - Customer customer = new Customer("Bob", "Builder", "21 Build Street"); - customerRepository.save(customer); + if (featureFlagService.writeToNewCustomerSchema()) { + NewCustomer customer = new NewCustomer("Bob", "Builder", "Build Street", "21"); + newCustomerRepository.save(customer); + } else { + OldCustomer customer = new OldCustomer("Bob", "Builder", "21 Build Street"); + oldCustomerRepository.save(customer); + } return "customer created"; } @GetMapping("/customers/list") String showUser() { - Iterable customers = customerRepository.findAll(); StringBuffer buffer = new StringBuffer(); - for (Customer customer : customers) { - buffer.append("\n"); - buffer.append(customer.toString()); + if (featureFlagService.readFromNewCustomerSchema()) { + Iterable customers = newCustomerRepository.findAll(); + for (NewCustomer customer : customers) { + buffer.append("\n"); + buffer.append(customer.toString()); + } + } else { + Iterable customers = oldCustomerRepository.findAll(); + for (OldCustomer customer : customers) { + buffer.append("\n"); + buffer.append(customer.toString()); + } } return buffer.toString(); } diff --git a/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/CustomerRepository.java b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/CustomerRepository.java index 81c9f15..8302e94 100644 --- a/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/CustomerRepository.java +++ b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/CustomerRepository.java @@ -2,5 +2,5 @@ package io.reflectoring.zerodowntime; import org.springframework.data.repository.CrudRepository; -public interface CustomerRepository extends CrudRepository { +public interface CustomerRepository extends CrudRepository { } diff --git a/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/FeatureFlagService.java b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/FeatureFlagService.java new file mode 100644 index 0000000..35837dc --- /dev/null +++ b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/FeatureFlagService.java @@ -0,0 +1,24 @@ +package io.reflectoring.zerodowntime; + +import com.launchdarkly.sdk.LDUser; +import com.launchdarkly.sdk.server.LDClient; +import org.springframework.stereotype.Component; + +@Component +public class FeatureFlagService { + + private final LDClient launchdarklyClient; + + public FeatureFlagService(LDClient launchdarklyClient) { + this.launchdarklyClient = launchdarklyClient; + } + + public Boolean writeToNewCustomerSchema() { + return true; + } + + public Boolean readFromNewCustomerSchema() { + return false; + } + +} \ No newline at end of file diff --git a/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/LaunchDarklyConfiguration.java b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/LaunchDarklyConfiguration.java new file mode 100644 index 0000000..7f7b82a --- /dev/null +++ b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/LaunchDarklyConfiguration.java @@ -0,0 +1,27 @@ +package io.reflectoring.zerodowntime; + +import com.launchdarkly.sdk.server.LDClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.PreDestroy; +import java.io.IOException; + +@Configuration +public class LaunchDarklyConfiguration { + + private LDClient launchdarklyClient; + + @Bean + public LDClient launchdarklyClient(@Value("${launchdarkly.sdkKey}") String sdkKey) { + this.launchdarklyClient = new LDClient(sdkKey); + return this.launchdarklyClient; + } + + @PreDestroy + public void destroy() throws IOException { + this.launchdarklyClient.close(); + } + +} \ No newline at end of file diff --git a/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/NewCustomer.java b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/NewCustomer.java new file mode 100644 index 0000000..b8a5f0c --- /dev/null +++ b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/NewCustomer.java @@ -0,0 +1,34 @@ +package io.reflectoring.zerodowntime; + + +import org.springframework.data.annotation.Id; +import org.springframework.data.relational.core.mapping.Table; + +@Table("CUSTOMER") +public class NewCustomer { + + @Id + private long id; + private String firstName; + private String lastName; + private String addressStreet; + private String addressStreetNumber; + + public NewCustomer(String firstName, String lastName, String addressStreet, String addressStreetNumber) { + this.firstName = firstName; + this.lastName = lastName; + this.addressStreet = addressStreet; + this.addressStreetNumber = addressStreetNumber; + } + + @Override + public String toString() { + return "NewCustomer{" + + "id=" + id + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", addressStreet='" + addressStreet + '\'' + + ", addressStreetNumber='" + addressStreetNumber + '\'' + + '}'; + } +} diff --git a/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/NewCustomerRepository.java b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/NewCustomerRepository.java new file mode 100644 index 0000000..70ad017 --- /dev/null +++ b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/NewCustomerRepository.java @@ -0,0 +1,6 @@ +package io.reflectoring.zerodowntime; + +import org.springframework.data.repository.CrudRepository; + +public interface NewCustomerRepository extends CrudRepository { +} diff --git a/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/Customer.java b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/OldCustomer.java similarity index 82% rename from spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/Customer.java rename to spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/OldCustomer.java index 1a40d61..f9f5008 100644 --- a/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/Customer.java +++ b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/OldCustomer.java @@ -5,7 +5,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.relational.core.mapping.Table; @Table("CUSTOMER") -public class Customer { +public class OldCustomer { @Id private long id; @@ -13,7 +13,7 @@ public class Customer { private String lastName; private String address; - public Customer(String firstName, String lastName, String address) { + public OldCustomer(String firstName, String lastName, String address) { this.firstName = firstName; this.lastName = lastName; this.address = address; @@ -21,7 +21,7 @@ public class Customer { @Override public String toString() { - return "Customer{" + + return "OldCustomer{" + "id=" + id + ", firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + diff --git a/spring-boot/zero-downtime/src/main/resources/application.yml b/spring-boot/zero-downtime/src/main/resources/application.yml index 1201da5..f31ca52 100644 --- a/spring-boot/zero-downtime/src/main/resources/application.yml +++ b/spring-boot/zero-downtime/src/main/resources/application.yml @@ -6,4 +6,7 @@ spring.jpa.database-platform: org.hibernate.dialect.H2Dialect spring: h2: console: - enabled: true \ No newline at end of file + enabled: true + +launchdarkly: + sdkKey: \ No newline at end of file diff --git a/spring-boot/zero-downtime/src/main/resources/db/migration/V002__add_address_columns.sql b/spring-boot/zero-downtime/src/main/resources/db/migration/V002__add_address_columns.sql new file mode 100644 index 0000000..eb5595f --- /dev/null +++ b/spring-boot/zero-downtime/src/main/resources/db/migration/V002__add_address_columns.sql @@ -0,0 +1,2 @@ +alter table customer add column address_street varchar(100) null; +alter table customer add column address_street_number varchar(100) null; From 375928575c79f16653a71835d6c62e66d6e0305a Mon Sep 17 00:00:00 2001 From: Tom Hombergs Date: Wed, 4 Aug 2021 06:33:14 +1000 Subject: [PATCH 2/4] zero-downtime example --- .../zerodowntime/CustomerController.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/CustomerController.java b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/CustomerController.java index 550a356..95ad61f 100644 --- a/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/CustomerController.java +++ b/spring-boot/zero-downtime/src/main/java/io/reflectoring/zerodowntime/CustomerController.java @@ -1,8 +1,11 @@ package io.reflectoring.zerodowntime; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; +import java.util.Optional; + @RestController public class CustomerController { @@ -17,7 +20,7 @@ public class CustomerController { } @GetMapping("/customers/create") - String createUser() { + String createCustomer() { if (featureFlagService.writeToNewCustomerSchema()) { NewCustomer customer = new NewCustomer("Bob", "Builder", "Build Street", "21"); newCustomerRepository.save(customer); @@ -28,8 +31,19 @@ public class CustomerController { return "customer created"; } + @GetMapping("/customers/{id}}") + String getCustomer(@PathVariable("id") Long id) { + if (featureFlagService.readFromNewCustomerSchema()) { + Optional customer = newCustomerRepository.findById(id); + return customer.get().toString(); + } else { + Optional customer = oldCustomerRepository.findById(id); + return customer.get().toString(); + } + } + @GetMapping("/customers/list") - String showUser() { + String getCustomer() { StringBuffer buffer = new StringBuffer(); if (featureFlagService.readFromNewCustomerSchema()) { Iterable customers = newCustomerRepository.findAll(); From 9cb21ffb8ac55b7e07515712491ffa105f089dd0 Mon Sep 17 00:00:00 2001 From: Tom Hombergs Date: Wed, 4 Aug 2021 06:33:55 +1000 Subject: [PATCH 3/4] zero-downtime example --- build-all.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/build-all.sh b/build-all.sh index 2958cc0..96d08d1 100755 --- a/build-all.sh +++ b/build-all.sh @@ -86,6 +86,7 @@ if [[ "$MODULE" == "module6" ]] then # ADD NEW MODULES HERE # (add new modules above the rest so you get quicker feedback if it fails) + build_maven_module "spring-boot/zero-downtime" build_maven_module "spring-boot/feature-flags" build maven_module "aws/springcloudses" build_gradle_module "aws/spring-cloud-caching-redis" From bf004661b0445b4017060be0b3ee8b70af518b2b Mon Sep 17 00:00:00 2001 From: Tom Hombergs Date: Wed, 4 Aug 2021 06:35:11 +1000 Subject: [PATCH 4/4] zero-downtime example --- build-all.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build-all.sh b/build-all.sh index 96d08d1..b52333f 100755 --- a/build-all.sh +++ b/build-all.sh @@ -88,9 +88,9 @@ then # (add new modules above the rest so you get quicker feedback if it fails) build_maven_module "spring-boot/zero-downtime" build_maven_module "spring-boot/feature-flags" - build maven_module "aws/springcloudses" + build_maven_module "aws/springcloudses" build_gradle_module "aws/spring-cloud-caching-redis" - build maven_module "spring-boot/spring-boot-camel" + build_maven_module "spring-boot/spring-boot-camel" build_maven_module "logging/spring-boot" build_maven_module "logging/logback" build_maven_module "logging/log4j" @@ -103,7 +103,7 @@ fi if [[ "$MODULE" == "module5" ]] then - build maven_module "aws/aws-dynamodb" + build_maven_module "aws/aws-dynamodb" build_maven_module "spring-boot/spring-boot-testconfiguration" build_maven_module "aws/springcloudrds" build_maven_module "aws/springcloudsqs"