Event migration improvements (#29514)
This commit is contained in:
parent
57fb9e9093
commit
728dda874e
14 changed files with 651 additions and 63 deletions
|
|
@ -224,7 +224,7 @@ needs to have an associated code which indicates if it is a window or aisle seat
|
|||
Adding fields is the most common change you'll need to apply to your messages so make sure the serialization format
|
||||
you picked for your payloads can handle it apropriately, i.e. such changes should be *binary compatible*.
|
||||
This is achieved using the right serializer toolkit. In the following examples we will be using protobuf.
|
||||
See also @ref:[how to add fields with Jackson](serialization-jackson.md#add-field).
|
||||
See also @ref:[how to add fields with Jackson](serialization-jackson.md#add-optional-field).
|
||||
|
||||
While being able to read messages with missing fields is half of the solution, you also need to deal with the missing
|
||||
values somehow. This is usually modeled as some kind of default value, or by representing the field as an @scala[`Option[T]`]@java[`Optional<T>`]
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ We will look at a few scenarios of how the classes may be evolved.
|
|||
Removing a field can be done without any migration code. The Jackson serializer will ignore properties that does
|
||||
not exist in the class.
|
||||
|
||||
### Add Field
|
||||
### Add Optional Field
|
||||
|
||||
Adding an optional field can be done without any migration code. The default value will be @scala[None]@java[`Optional.empty`].
|
||||
|
||||
|
|
@ -226,6 +226,8 @@ Scala
|
|||
Java
|
||||
: @@snip [ItemAdded.java](/akka-serialization-jackson/src/test/java/jdoc/akka/serialization/jackson/v2a/ItemAdded.java) { #add-optional }
|
||||
|
||||
### Add Mandatory Field
|
||||
|
||||
Let's say we want to have a mandatory `discount` property without default value instead:
|
||||
|
||||
Scala
|
||||
|
|
@ -361,6 +363,63 @@ binding, but it should still be possible to deserialize old data with Jackson.
|
|||
|
||||
It's a list of class names or prefixes of class names.
|
||||
|
||||
## Rolling updates
|
||||
|
||||
When doing a rolling update, for a period of time there are two different binaries running in production. If the schema
|
||||
has evolved requiring a new schema version, the data serialized by the new binary will be unreadable from the old
|
||||
binary. This situation causes transient errors on the processes running the old binary. This service degradation is
|
||||
usually fine since the rolling update will eventually complete and all old processes will be replaced with the new
|
||||
binary. To avoid this service degradation you can also use forward-one support in your schema evolutions.
|
||||
|
||||
To complete a no-degradation rolling update, you need to make two deployments. First, deploy a new binary which can read
|
||||
the new schema but still uses the old schema. Then, deploy a second binary which serializes data using the new schema
|
||||
and drops the downcasting code from the migration.
|
||||
|
||||
Let's take, for example, the case above where we [renamed a field](#rename-field).
|
||||
|
||||
The starting schema is:
|
||||
|
||||
Scala
|
||||
: @@snip [ItemAdded.java](/akka-serialization-jackson/src/test/scala/doc/akka/serialization/jackson/v1/ItemAdded.scala) { #add-optional }
|
||||
|
||||
Java
|
||||
: @@snip [ItemAdded.java](/akka-serialization-jackson/src/test/java/jdoc/akka/serialization/jackson/v1/ItemAdded.java) { #add-optional }
|
||||
|
||||
In a first deployment, we still don't make any change to the event class:
|
||||
|
||||
Scala
|
||||
: @@snip [ItemAdded.scala](/akka-serialization-jackson/src/test/scala/doc/akka/serialization/jackson/v1/ItemAdded.scala) { #forward-one-rename }
|
||||
|
||||
Java
|
||||
: @@snip [ItemAdded.java](/akka-serialization-jackson/src/test/java/jdoc/akka/serialization/jackson/v1/ItemAdded.java) { #forward-one-rename }
|
||||
|
||||
but we introduce a migration that can read the newer schema which is versioned `2`:
|
||||
|
||||
Scala
|
||||
: @@snip [ItemAddedMigration.scala](/akka-serialization-jackson/src/test/scala/doc/akka/serialization/jackson/v1withv2/ItemAddedMigration.scala) { #forward-one-rename }
|
||||
|
||||
Java
|
||||
: @@snip [ItemAddedMigration.java](/akka-serialization-jackson/src/test/java/jdoc/akka/serialization/jackson/v1withv2/ItemAddedMigration.java) { #forward-one-rename }
|
||||
|
||||
Once all running nodes have the new migration code which can read version `2` of `ItemAdded` we can proceed with the
|
||||
second step. So, we deploy the updated event:
|
||||
|
||||
Scala
|
||||
: @@snip [ItemAdded.scala](/akka-serialization-jackson/src/test/scala/doc/akka/serialization/jackson/v2c/ItemAdded.scala) { #rename }
|
||||
|
||||
Java
|
||||
: @@snip [ItemAdded.java](/akka-serialization-jackson/src/test/java/jdoc/akka/serialization/jackson/v2c/ItemAdded.java) { #rename }
|
||||
|
||||
and the final migration code which no longer needs forward-compatibility code:
|
||||
|
||||
Scala
|
||||
: @@snip [ItemAddedMigration.scala](/akka-serialization-jackson/src/test/scala/doc/akka/serialization/jackson/v2c/ItemAddedMigration.scala) { #rename }
|
||||
|
||||
Java
|
||||
: @@snip [ItemAddedMigration.java](/akka-serialization-jackson/src/test/java/jdoc/akka/serialization/jackson/v2c/ItemAddedMigration.java) { #rename }
|
||||
|
||||
|
||||
|
||||
## Jackson Modules
|
||||
|
||||
The following Jackson modules are enabled by default:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue