From eddc61af829290bbe5d714ff5e7dbd71110b60a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Klang=20=28=E2=88=9A=29?= Date: Tue, 5 Jun 2018 10:49:01 +0200 Subject: [PATCH] Documentation updates for Akka Persistence Typed (#25194) * Switching to throwing exceptions in documentation suggestions --- .../src/main/paradox/typed/persistence.md | 31 +++++++------- .../typed/BasicPersistentBehaviorsTest.java | 13 +++--- .../BasicPersistentBehaviorsCompileOnly.scala | 41 +++++++++++++------ 3 files changed, 52 insertions(+), 33 deletions(-) diff --git a/akka-docs/src/main/paradox/typed/persistence.md b/akka-docs/src/main/paradox/typed/persistence.md index eb77e7a1d6..33bd71d31c 100644 --- a/akka-docs/src/main/paradox/typed/persistence.md +++ b/akka-docs/src/main/paradox/typed/persistence.md @@ -41,10 +41,10 @@ The event and state are only used internally. The components that make up a PersistentBehavior are: -* `persistenceId` is the unique identifier for the persistent actor. +* `persistenceId` is the stable unique identifier for the persistent actor. * `emptyState` defines the `State` when the entity is first created e.g. a Counter would start with 0 as state. -* `commandHandler` defines how to handle command, resulting in Effects e.g. persisting events, stopping the persistent actor. -* `eventHandler` updates the current state when an event has been persisted. +* `commandHandler` defines how to handle command by producing Effects e.g. persisting events, stopping the persistent actor. +* `eventHandler` returns the new state given the current state when an event has been persisted. Next we'll discuss each of these in detail. @@ -62,8 +62,7 @@ and can be used to create various effects such as: * `none` no events are to be persisted, for example a read-only command * `unhandled` the command is unhandled (not supported) in current state -External side effects can be performed after successful persist with the `andThen` function e.g -@scala[`Effect.persist(..).andThen`]@java[`Effect().persist(..).andThen`]. +External side effects are to be performed after successful persist which is achieved with the `andThen` function e.g @scala[`Effect.persist(..).andThen`]@java[`Effect().persist(..).andThen`]. In the example below a reply is sent to the `replyTo` ActorRef. Note that the new state after applying the event is passed as parameter to the `andThen` function. All `andThen*` registered callbacks @@ -71,8 +70,7 @@ are executed after successful execution of the persist statement (or immediately ### Event handler -When an event has been persisted successfully the current state is updated by applying the -event to the current state with the `eventHandler`. +When an event has been persisted successfully the new state is created by applying the event to the current state with the `eventHandler`. The event handler returns the new state, which must be immutable so you return a new instance of the state. The same event handler is also used when the entity is started up to recover its state from the stored events. @@ -123,11 +121,11 @@ Scala Java : @@snip [PersistentActorCompileOnyTest.java]($akka$/akka-persistence-typed/src/test/java/akka/persistence/typed/javadsl/PersistentActorCompileOnlyTest.java) { #behavior } -The behavior can then be run as with any normal typed actor as described in [typed actors documentation](actors-typed.md). +The `PersistentBehavior` can then be run as with any plain typed actor as described in [typed actors documentation](actors-typed.md). ## Larger example -After processing a message plain typed actors are able to return the `Behavior` that is used +After processing a message, plain typed actors are able to return the `Behavior` that is used for next message. As you can see in the above examples this is not supported by typed persistent actors. Instead, the state is @@ -136,7 +134,7 @@ state and must also carefully be reconstructed during recovery. If it would have that the behavior must be restored when replaying events and also encoded in the state anyway when snapshots are used. That would be very prone to mistakes and thus not allowed in Typed Persistence. -For simple actors you can use the same set of command handlers independent of what state the entity is in, +For basic actors you can use the same set of command handlers independent of what state the entity is in, as shown in above example. For more complex actors it's useful to be able to change the behavior in the sense that different functions for processing commands may be defined depending on what state the actor is in. This is useful when implementing finite state machine (FSM) like entities. @@ -152,7 +150,7 @@ Scala Java : @@snip [InDepthPersistentBehaviorTest.java]($akka$/akka-persistence-typed/src/test/java/jdocs/akka/persistence/typed/InDepthPersistentBehaviorTest.java) { #state } -The commands (only a subset are valid depending on state): +The commands, of which only a subset are valid depending on the state: Scala : @@snip [InDepthPersistentBehaviorSpec.scala]($akka$/akka-persistence-typed/src/test/scala/docs/akka/persistence/typed/InDepthPersistentBehaviorSpec.scala) { #commands } @@ -186,8 +184,8 @@ Java : @@snip [InDepthPersistentBehaviorTest.java]($akka$/akka-persistence-typed/src/test/java/jdocs/akka/persistence/typed/InDepthPersistentBehaviorTest.java) { #post-added-command-handler } The event handler is always the same independent of state. The main reason for not making the event handler -part of the `CommandHandler` is that all events must be handled and that is typically independent of what the -current state is. The event handler can still decide what to do based on the state if that is needed. +part of the `CommandHandler` is that contrary to Commands, all events must be handled and that is typically independent of what the +current state is. The event handler can still decide what to do based on the state, if that is needed. Scala : @@snip [InDepthPersistentBehaviorSpec.scala]($akka$/akka-persistence-typed/src/test/scala/docs/akka/persistence/typed/InDepthPersistentBehaviorSpec.scala) { #event-handler } @@ -212,8 +210,8 @@ Strategies for that can be found in the @ref:[schema evolution](../persistence-s ## Recovery -Since it is strongly discouraged to perform side effects in applyEvent, -side effects should be performed once recovery has completed @scala[in the `onRecoveryCompleted` callback.] @java[by overriding `onRecoveryCompleted`] +It is strongly discouraged to perform side effects in `applyEvent`, +so side effects should be performed once recovery has completed @scala[in the `onRecoveryCompleted` callback.] @java[by overriding `onRecoveryCompleted`] Scala : @@snip [BasicPersistentBehaviorsCompileOnly.scala]($akka$/akka-persistence-typed/src/test/scala/docs/akka/persistence/typed/BasicPersistentBehaviorsCompileOnly.scala) { #recovery } @@ -221,7 +219,8 @@ Scala Java : @@snip [BasicPersistentBehaviorsTest.java]($akka$/akka-persistence-typed/src/test/java/jdocs/akka/persistence/typed/BasicPersistentBehaviorsTest.java) { #recovery } -The `onRecoveryCompleted` takes on an `ActorContext` and the current `State`. +The `onRecoveryCompleted` takes on an `ActorContext` and the current `State`, +and doesn't return anything. ## Tagging diff --git a/akka-persistence-typed/src/test/java/jdocs/akka/persistence/typed/BasicPersistentBehaviorsTest.java b/akka-persistence-typed/src/test/java/jdocs/akka/persistence/typed/BasicPersistentBehaviorsTest.java index 2b008e75ff..cc41216956 100644 --- a/akka-persistence-typed/src/test/java/jdocs/akka/persistence/typed/BasicPersistentBehaviorsTest.java +++ b/akka-persistence-typed/src/test/java/jdocs/akka/persistence/typed/BasicPersistentBehaviorsTest.java @@ -35,26 +35,29 @@ public class BasicPersistentBehaviorsTest { @Override public CommandHandler commandHandler() { - return (ctx, state, command) -> Effect().none(); + return (ctx, state, command) -> { + throw new RuntimeException("TODO: process the command & return an Effect"); + }; } @Override public EventHandler eventHandler() { - return (state, event) -> state; + return (state, event) -> { + throw new RuntimeException("TODO: process the event return the next state"); + }; } //#recovery @Override public void onRecoveryCompleted(ActorContext ctx, State state) { - // called once recovery is completed + throw new RuntimeException("TODO: add some end-of-recovery side-effect here"); } //#recovery //#tagging @Override public Set tagsFor(Event event) { - // inspect the event and decide if it should be tagged - return Collections.emptySet(); + throw new RuntimeException("TODO: inspect the event and return any tags it should have"); } //#tagging } diff --git a/akka-persistence-typed/src/test/scala/docs/akka/persistence/typed/BasicPersistentBehaviorsCompileOnly.scala b/akka-persistence-typed/src/test/scala/docs/akka/persistence/typed/BasicPersistentBehaviorsCompileOnly.scala index 38a9b9a546..102c5309c3 100644 --- a/akka-persistence-typed/src/test/scala/docs/akka/persistence/typed/BasicPersistentBehaviorsCompileOnly.scala +++ b/akka-persistence-typed/src/test/scala/docs/akka/persistence/typed/BasicPersistentBehaviorsCompileOnly.scala @@ -19,8 +19,13 @@ object BasicPersistentBehaviorsCompileOnly { PersistentBehaviors.receive[Command, Event, State]( persistenceId = "abc", emptyState = State(), - commandHandler = (ctx, state, cmd) ⇒ ???, - eventHandler = (state, evt) ⇒ ???) + commandHandler = + (ctx, state, cmd) ⇒ + throw new RuntimeException("TODO: process the command & return an Effect"), + eventHandler = + (state, evt) ⇒ + throw new RuntimeException("TODO: process the event return the next state") + ) //#structure //#recovery @@ -28,10 +33,14 @@ object BasicPersistentBehaviorsCompileOnly { PersistentBehaviors.receive[Command, Event, State]( persistenceId = "abc", emptyState = State(), - commandHandler = (ctx, state, cmd) ⇒ ???, - eventHandler = (state, evt) ⇒ ???) - .onRecoveryCompleted { (ctx, state) ⇒ - ??? + commandHandler = + (ctx, state, cmd) ⇒ + throw new RuntimeException("TODO: process the command & return an Effect"), + eventHandler = + (state, evt) ⇒ + throw new RuntimeException("TODO: process the event return the next state") + ).onRecoveryCompleted { (ctx, state) ⇒ + throw new RuntimeException("TODO: add some end-of-recovery side-effect here") } //#recovery @@ -40,8 +49,12 @@ object BasicPersistentBehaviorsCompileOnly { PersistentBehaviors.receive[Command, Event, State]( persistenceId = "abc", emptyState = State(), - commandHandler = (ctx, state, cmd) ⇒ ???, - eventHandler = (state, evt) ⇒ ??? + commandHandler = + (ctx, state, cmd) ⇒ + throw new RuntimeException("TODO: process the command & return an Effect"), + eventHandler = + (state, evt) ⇒ + throw new RuntimeException("TODO: process the event return the next state") ).withTagger(_ ⇒ Set("tag1", "tag2")) //#tagging @@ -50,10 +63,14 @@ object BasicPersistentBehaviorsCompileOnly { val samplePersistentBehavior = PersistentBehaviors.receive[Command, Event, State]( persistenceId = "abc", emptyState = State(), - commandHandler = (ctx, state, cmd) ⇒ ???, - eventHandler = (state, evt) ⇒ ???) - .onRecoveryCompleted { (ctx, state) ⇒ - ??? + commandHandler = + (ctx, state, cmd) ⇒ + throw new RuntimeException("TODO: process the command & return an Effect"), + eventHandler = + (state, evt) ⇒ + throw new RuntimeException("TODO: process the event return the next state") + ).onRecoveryCompleted { (ctx, state) ⇒ + throw new RuntimeException("TODO: add some end-of-recovery side-effect here") } val debugAlwaysSnapshot: Behavior[Command] = Behaviors.setup {