From 79ffae1e6f6304698b0bb1aa4432bb0331f259d5 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 16 Dec 2025 20:21:14 +0100 Subject: [PATCH] try to reduce confusion about signals in persistence implementations (#2585) * try to reduce confusion about signals in persistence implementations * Update persistence.md --- docs/src/main/paradox/typed/durable-state/persistence.md | 7 +++++++ docs/src/main/paradox/typed/persistence.md | 4 ++-- .../persistence/typed/BasicPersistentBehaviorTest.java | 3 +-- .../typed/BasicPersistentBehaviorCompileOnly.scala | 3 +-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/src/main/paradox/typed/durable-state/persistence.md b/docs/src/main/paradox/typed/durable-state/persistence.md index d36bc42209..1ee5813eb3 100644 --- a/docs/src/main/paradox/typed/durable-state/persistence.md +++ b/docs/src/main/paradox/typed/durable-state/persistence.md @@ -199,6 +199,13 @@ Scala Java : @@snip [PersistentActorCompileOnlyTest.java](/persistence-typed/src/test/java/org/apache/pekko/persistence/typed/javadsl/PersistentActorCompileOnlyTest.java) { #commonChainedEffects } +### DurableStateBehavior receiveSignal/signalHandler + +DurableStateBehavior supports receiveSignal/signalHandler in a similar way to EventSourcedBehavior but the signal classes are in the `org.apache.pekko.persistence.typed.state` package not the `org.apache.pekko.persistence.typed` package. These are the only `DurableStateSignal` signals and note that the class names match equivalent `EventSourcedSignal` classes but you need to use these ones for DurableStateBehavior: + +* @apidoc[pekko.persistence.typed.state.RecoveryCompleted] signal +* @apidoc[pekko.persistence.typed.state.RecoveryFailed] signal + ### Side effects ordering and guarantees Any side effects are executed on an at-most-once basis and will not be executed if the persist fails. diff --git a/docs/src/main/paradox/typed/persistence.md b/docs/src/main/paradox/typed/persistence.md index a58d350a93..3e4c2aea65 100644 --- a/docs/src/main/paradox/typed/persistence.md +++ b/docs/src/main/paradox/typed/persistence.md @@ -471,7 +471,7 @@ pekko.persistence.max-concurrent-recoveries = 50 The @ref:[event handler](#event-handler) is used for updating the state when replaying the journaled events. It is strongly discouraged to perform side effects in the event handler, so side effects should be performed -once recovery has completed as a reaction to the @apidoc[typed.RecoveryCompleted] signal @scala[in the @scaladoc[receiveSignal](pekko.persistence.typed.scaladsl.EventSourcedBehavior#receiveSignal(signalHandler:PartialFunction[(State,org.apache.pekko.actor.typed.Signal),Unit]):org.apache.pekko.persistence.typed.scaladsl.EventSourcedBehavior[Command,Event,State]) handler] @java[by overriding @javadoc[receiveSignal](pekko.persistence.typed.javadsl.SignalHandlerBuilder#onSignal(java.lang.Class,java.util.function.BiConsumer))] +once recovery has completed as a reaction to the @apidoc[typed.RecoveryCompleted] signal @scala[in the @scaladoc[receiveSignal](pekko.persistence.typed.scaladsl.EventSourcedBehavior#receiveSignal(signalHandler:PartialFunction[(State,org.apache.pekko.actor.typed.Signal),Unit]):org.apache.pekko.persistence.typed.scaladsl.EventSourcedBehavior[Command,Event,State]) handler] @java[by overriding @javadoc[signalHandler](pekko.persistence.typed.javadsl.SignalHandlerBuilder#onSignal(java.lang.Class,java.util.function.BiConsumer))] Scala : @@snip [BasicPersistentBehaviorCompileOnly.scala](/persistence-typed/src/test/scala/docs/org/apache/pekko/persistence/typed/BasicPersistentBehaviorCompileOnly.scala) { #recovery } @@ -481,7 +481,7 @@ Java The `RecoveryCompleted` contains the current `State`. -The actor will always receive a `RecoveryCompleted` signal, even if there are no events +The actor will always receive a @apidoc[typed.RecoveryCompleted] signal, even if there are no events in the journal and the snapshot store is empty, or if it's a new persistent actor with a previously unused `PersistenceId`. diff --git a/persistence-typed/src/test/java/jdocs/org/apache/pekko/persistence/typed/BasicPersistentBehaviorTest.java b/persistence-typed/src/test/java/jdocs/org/apache/pekko/persistence/typed/BasicPersistentBehaviorTest.java index 5e5f77d15a..79f16eb8d2 100644 --- a/persistence-typed/src/test/java/jdocs/org/apache/pekko/persistence/typed/BasicPersistentBehaviorTest.java +++ b/persistence-typed/src/test/java/jdocs/org/apache/pekko/persistence/typed/BasicPersistentBehaviorTest.java @@ -20,7 +20,6 @@ import org.apache.pekko.actor.typed.javadsl.Behaviors; import org.apache.pekko.persistence.typed.DeleteEventsFailed; import org.apache.pekko.persistence.typed.DeleteSnapshotsFailed; -import org.apache.pekko.persistence.typed.RecoveryCompleted; import org.apache.pekko.persistence.typed.SnapshotFailed; import org.apache.pekko.persistence.typed.SnapshotSelectionCriteria; import org.apache.pekko.persistence.typed.javadsl.CommandHandler; @@ -347,7 +346,7 @@ public EventHandler eventHandler() { public SignalHandler signalHandler() { return newSignalHandlerBuilder() .onSignal( - RecoveryCompleted.instance(), + org.apache.pekko.persistence.typed.RecoveryCompleted.instance(), state -> { throw new RuntimeException("TODO: add some end-of-recovery side-effect here"); }) diff --git a/persistence-typed/src/test/scala/docs/org/apache/pekko/persistence/typed/BasicPersistentBehaviorCompileOnly.scala b/persistence-typed/src/test/scala/docs/org/apache/pekko/persistence/typed/BasicPersistentBehaviorCompileOnly.scala index a24ce49f74..cef1a82885 100644 --- a/persistence-typed/src/test/scala/docs/org/apache/pekko/persistence/typed/BasicPersistentBehaviorCompileOnly.scala +++ b/persistence-typed/src/test/scala/docs/org/apache/pekko/persistence/typed/BasicPersistentBehaviorCompileOnly.scala @@ -35,7 +35,6 @@ import pekko.persistence.typed.PersistenceId //#behavior //#structure import org.apache.pekko -import pekko.persistence.typed.RecoveryCompleted import pekko.persistence.typed.SnapshotFailed import scala.annotation.nowarn @@ -128,7 +127,7 @@ object BasicPersistentBehaviorCompileOnly { commandHandler = (state, cmd) => throw new NotImplementedError("TODO: process the command & return an Effect"), eventHandler = (state, evt) => throw new NotImplementedError("TODO: process the event return the next state")) .receiveSignal { - case (state, RecoveryCompleted) => + case (state, pekko.persistence.typed.RecoveryCompleted) => throw new NotImplementedError("TODO: add some end-of-recovery side-effect here") } // #recovery