This repository has been archived by the owner on Apr 20, 2022. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 3931cb5
Showing
34 changed files
with
1,075 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
*~ | ||
#* | ||
*# | ||
.#* | ||
.classpath | ||
.project | ||
.settings/ | ||
.springBeans | ||
target/ | ||
_site/ | ||
.idea | ||
*.iml | ||
*.swp | ||
.factorypath | ||
*.logtjmeter | ||
.checkstyle | ||
.DS_Store | ||
*.log | ||
/spring-cloud-sleuth-core/nb-configuration.xml | ||
/spring-cloud-sleuth-core/nbactions.xml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
= Database Update | ||
|
||
How to write the code of your app to allow doing A/B testing or/and continuous deployment. | ||
|
||
== Assumptions | ||
|
||
In order for the process to be relatively simple the following assumptions need to take place | ||
while developing the app: | ||
|
||
- use a database versioning tool (we'll be using https://flywaydb.org[Flyway]) | ||
- the database changes need to be backwards compatible | ||
- if you want to do a backwards incompatible change you have to do it in a couple of deployments | ||
- we don't want to do DB rollbacks. Not doing them simplifies the deployment process (some rollbacks are close to impossible like rolling back a delete) | ||
- we want to ALWAYS be able to rollback the application one version back (not more) | ||
|
||
== The issue | ||
|
||
For readability we're versioning the apps with major increments. | ||
|
||
Why is this problem worth discussing? Doing A/B testing with Cloud Foundry is extremely simple - it's a matter of executing a single command. However it's not that trivial in terms of the application and the db. | ||
|
||
Let's take a look at the following example if you want to change the column name: | ||
|
||
WARNING: The following example is deliberately done in such a way that it will break. We're showing it to depict the problem of database compatibility. | ||
|
||
=== Changing the column name in backwards-incompatible way | ||
|
||
Let's assume that we have the DB in version `v1`. It has the column with a name `last_name`. We want to change it to `surname.` We have the app in version `1.0.0` which uses the `last_name` column in the code. | ||
|
||
==== Rolling a new backwards-incompatible version | ||
|
||
. in Flyway we're writing a script to change the column name from `last_name` to `surname` | ||
. we're writing our code to use the new `surname` column | ||
|
||
==== A/B testing | ||
|
||
The current situation is that we have an app deployed to production in version `1.0.0` and db in `v1`. We want to deploy the second instance of the app that will be in version `2.0.0` and update the db to `v2`. | ||
|
||
Steps: | ||
|
||
. a new instance is deployed in version `2.0.0` that updates the db to `v2` | ||
. in `v2` of the database the column `last_name` is no longer existing - it got changed to `surname` | ||
. the db and app upgrade is successful and you have some instances working in `1.0.0`, others in `2.0.0`. All are talking to db in `v2` | ||
. all instances of version `1.0.0` will start producing exceptions cause they will try to insert data to `last_name` column which is no longer there | ||
. all instances of version `2.0.0` will work without any issues | ||
|
||
As you can if we do backwards incompatible changes of the DB and the application, A/B testing is impossible. | ||
|
||
==== Rolling back the application | ||
|
||
Let's assume that after trying to do A/B deployment we've decided that we need to rollback the app back to version `1.0.0`. We assumed that we don't want to roll back the database. | ||
|
||
Steps: | ||
|
||
. we shut down the instance that was running with version `2.0.0` | ||
. the database is still in `v2` | ||
. since version `1.0.0` doesn't understand what `surname` column is it will produce exceptions | ||
. hell broke loose and we can't go back | ||
|
||
As you can if we do backwards incompatible changes of the DB and the application, we can't roll back to a previous version. | ||
|
||
== Proper database update flow | ||
|
||
INFO: Here we'll present a more sound approach to deployment | ||
|
||
=== Adding a new column | ||
|
||
This situation is quite simple. Let's assume that we have the DB in version `v1`. It doesn't have the column `surname`. | ||
We also have the app in version `1.0.0` which doesn't use the `surname` column. | ||
|
||
==== Rolling a new version | ||
|
||
Steps: | ||
|
||
. migrate your db to create the new column called `surname`. Now your db is in `v2` | ||
. write the code to use the new column. Now your app is in version `2.0.0` | ||
|
||
If you're using Spring Boot Flyway those two steps will be performed upon booting the version `2.0.0` of the app. If you're running database versioning tool manually then you'd have to do it in separate processes (first manually upgrade the db version and then deploy the new app). | ||
|
||
==== A/B testing | ||
|
||
The current situation is that we have an app deployed to production in version `1.0.0` and db in `v1`. We want to deploy the second instance of the app that will be in version `2.0.0` and update the db to `v2`. | ||
|
||
Steps: | ||
|
||
. a new instance is deployed in version `2.0.0` that updates the db to `v2` | ||
. in the meantime some requests got processed by instances being in version `1.0.0` | ||
. the upgrade is successful and you have some instances working in `1.0.0`, others in `2.0.0`. All are talking to db in `v2` | ||
. version `1.0.0` is not using the database's column `surname` and version `2.0.0` is. They don't interfere each other, no exceptions should be thrown. | ||
|
||
==== Rolling back the application | ||
|
||
The current situation is that we have app in version `2.0.0` and db in `v2`. | ||
|
||
Steps: | ||
|
||
. roll back your app to version `1.0.0`. | ||
. version `1.0.0` is not using the database's column `surname` thus rollback should be successful | ||
|
||
== Projects | ||
|
||
We will focus on the most interesting case of changing the column name. That change is backwards | ||
incompatible but we'll try to write it in such a way that A/B testing is possible. | ||
|
||
[source,bash] | ||
------- | ||
├── boot-flyway-v1 - 1.0.0 version of the app with v1 of the schema | ||
├── boot-flyway-v2 - 2.0.0 version of the app with v2 of the schema (backwards-compatible - app can be rolled back) | ||
├── boot-flyway-v2-bad - 2.0.0 version of the app with v2 of the schema (backwards-incompatible - app can't be rolled back) | ||
└── boot-flyway-v3 - 3.0.0. version of the app with v3 of the schema (app can be rolled back) | ||
------- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
== Spring Boot Flyway Sample | ||
|
||
This sample demonstrates the flyway auto-configuration support. | ||
|
||
You can look at `http://localhost:8080/flyway` to review the list of scripts. | ||
|
||
This sample also enables the H2 console (at `http://localhost:8080/h2-console`) | ||
so that you can review the state of the database (the default jdbc url is | ||
`jdbc:h2:mem:testdb`). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<!-- Your own application should inherit from spring-boot-starter-parent --> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-parent</artifactId> | ||
<version>1.3.3.RELEASE</version> | ||
</parent> | ||
<artifactId>spring-boot-sample-flyway</artifactId> | ||
<name>Spring Boot Flyway Sample</name> | ||
<description>Spring Boot Flyway Sample</description> | ||
<url>http://projects.spring.io/spring-boot/</url> | ||
<organization> | ||
<name>Pivotal Software, Inc.</name> | ||
<url>http://www.spring.io</url> | ||
</organization> | ||
<properties> | ||
<main.basedir>${basedir}/../..</main.basedir> | ||
</properties> | ||
<dependencies> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-data-jpa</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-web</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-actuator</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.flywaydb</groupId> | ||
<artifactId>flyway-core</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>com.h2database</groupId> | ||
<artifactId>h2</artifactId> | ||
<scope>runtime</scope> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-test</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-maven-plugin</artifactId> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
* Copyright 2012-2015 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package sample.flyway; | ||
|
||
import javax.persistence.Entity; | ||
import javax.persistence.GeneratedValue; | ||
import javax.persistence.Id; | ||
|
||
@Entity | ||
public class Person { | ||
@Id | ||
@GeneratedValue | ||
private Long id; | ||
private String firstName; | ||
private String lastName; | ||
|
||
public String getFirstName() { | ||
return this.firstName; | ||
} | ||
|
||
public void setFirstName(String firstName) { | ||
this.firstName = firstName; | ||
} | ||
|
||
public String getLastName() { | ||
return this.lastName; | ||
} | ||
|
||
public void setLastName(String lastname) { | ||
this.lastName = lastname; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "Person [firstName=" + this.firstName + ", lastName=" + this.lastName | ||
+ "]"; | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
boot-flyway-v1/src/main/java/sample/flyway/PersonRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
* Copyright 2012-2015 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package sample.flyway; | ||
|
||
import org.springframework.data.repository.CrudRepository; | ||
import org.springframework.stereotype.Repository; | ||
|
||
@Repository | ||
public interface PersonRepository extends CrudRepository<Person, Long> { | ||
|
||
} |
39 changes: 39 additions & 0 deletions
39
boot-flyway-v1/src/main/java/sample/flyway/SampleFlywayApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* | ||
* Copyright 2012-2015 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package sample.flyway; | ||
|
||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.CommandLineRunner; | ||
import org.springframework.boot.SpringApplication; | ||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
|
||
@SpringBootApplication | ||
public class SampleFlywayApplication implements CommandLineRunner { | ||
|
||
@Autowired | ||
private PersonRepository repository; | ||
|
||
@Override | ||
public void run(String... args) throws Exception { | ||
System.err.println(this.repository.findAll()); | ||
} | ||
|
||
public static void main(String[] args) throws Exception { | ||
SpringApplication.run(SampleFlywayApplication.class, args); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
spring.jpa.hibernate.ddl-auto=validate | ||
|
||
spring.h2.console.enabled=true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
CREATE TABLE PERSON ( | ||
id BIGINT GENERATED BY DEFAULT AS IDENTITY, | ||
first_name varchar(255) not null, | ||
last_name varchar(255) not null | ||
); | ||
|
||
insert into PERSON (first_name, last_name) values ('Dave', 'Syer'); |
42 changes: 42 additions & 0 deletions
42
boot-flyway-v1/src/test/java/sample/flyway/SampleFlywayApplicationTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright 2012-2014 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package sample.flyway; | ||
|
||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
|
||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.SpringApplicationConfiguration; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
|
||
@RunWith(SpringJUnit4ClassRunner.class) | ||
@SpringApplicationConfiguration(SampleFlywayApplication.class) | ||
public class SampleFlywayApplicationTests { | ||
|
||
@Autowired | ||
private JdbcTemplate template; | ||
|
||
@Test | ||
public void testDefaultSettings() throws Exception { | ||
assertEquals(new Integer(1), this.template | ||
.queryForObject("SELECT COUNT(*) from PERSON", Integer.class)); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
== Spring Boot Flyway Sample | ||
|
||
This sample demonstrates the flyway auto-configuration support. | ||
|
||
You can look at `http://localhost:8080/flyway` to review the list of scripts. | ||
|
||
This sample also enables the H2 console (at `http://localhost:8080/h2-console`) | ||
so that you can review the state of the database (the default jdbc url is | ||
`jdbc:h2:mem:testdb`). |
Oops, something went wrong.