diff --git a/akka-docs/src/main/paradox/cluster-usage.md b/akka-docs/src/main/paradox/cluster-usage.md index 740dfdc1ea..a866aa9242 100644 --- a/akka-docs/src/main/paradox/cluster-usage.md +++ b/akka-docs/src/main/paradox/cluster-usage.md @@ -9,11 +9,15 @@ For specific documentation topics see: * @ref:[Higher level Cluster tools](#higher-level-cluster-tools) * @ref:[Rolling Updates](additional/rolling-updates.md) * @ref:[Operating, Managing, Observability](additional/operations.md) - -Enable @ref:[serialization](serialization.md) to send events between ActorSystems and systems -external to the Cluster. @ref:[Serialization with Jackson](serialization-jackson.md) is a good choice in many cases, and our + +@@@ note + +You have to enable @ref:[serialization](serialization.md) to send messages between ActorSystems in the Cluster. +@ref:[Serialization with Jackson](serialization-jackson.md) is a good choice in many cases, and our recommendation if you don't have other preferences or constraints. +@@@ + ## Dependency To use Akka Cluster add the following dependency in your project: diff --git a/akka-docs/src/main/paradox/index-cluster.md b/akka-docs/src/main/paradox/index-cluster.md index 415c3db7ce..3698320f7f 100644 --- a/akka-docs/src/main/paradox/index-cluster.md +++ b/akka-docs/src/main/paradox/index-cluster.md @@ -15,6 +15,7 @@ For the new API see @ref[Cluster](typed/index-cluster.md). * [cluster-sharding](cluster-sharding.md) * [cluster-metrics](cluster-metrics.md) * [distributed-data](distributed-data.md) +* [serialization](serialization-classic.md) * [coordination](coordination.md) @@@ diff --git a/akka-docs/src/main/paradox/serialization-classic.md b/akka-docs/src/main/paradox/serialization-classic.md new file mode 100644 index 0000000000..01debcb51e --- /dev/null +++ b/akka-docs/src/main/paradox/serialization-classic.md @@ -0,0 +1,78 @@ +# Classic Serialization + +@@include[includes.md](includes.md) { #actor-api } + +Serialization is the same for Classic and Typed actors. It is described in @ref:[Serialization](serialization.md), +aside from serialization of `ActorRef` that is described @ref:[here](#serializing-actorrefs). + +## Dependency + +To use Serialization, you must add the following dependency in your project: + +@@dependency[sbt,Maven,Gradle] { + group="com.typesafe.akka" + artifact="akka-actor_$scala.binary_version$" + version="$akka.version$" +} + +## Serializing ActorRefs + +All ActorRefs are serializable when using @ref:[Serialization with Jackson](serialization-jackson.md), +but in case you are writing your own serializer, you might want to know how to serialize and deserialize them properly. +In the general case, the local address to be used depends on the type of remote +address which shall be the recipient of the serialized information. Use +`Serialization.serializedActorPath(actorRef)` like this: + +Scala +: @@snip [SerializationDocSpec.scala](/akka-docs/src/test/scala/docs/serialization/SerializationDocSpec.scala) { #imports } + +Java +: @@snip [SerializationDocTest.java](/akka-docs/src/test/java/jdocs/serialization/SerializationDocTest.java) { #imports } + + +Scala +: @@snip [SerializationDocSpec.scala](/akka-docs/src/test/scala/docs/serialization/SerializationDocSpec.scala) { #actorref-serializer } + +Java +: @@snip [SerializationDocTest.java](/akka-docs/src/test/java/jdocs/serialization/SerializationDocTest.java) { #actorref-serializer } + +This assumes that serialization happens in the context of sending a message +through the remote transport. There are other uses of serialization, though, +e.g. storing actor references outside of an actor application (database, etc.). +In this case, it is important to keep in mind that the +address part of an actor’s path determines how that actor is communicated with. +Storing a local actor path might be the right choice if the retrieval happens +in the same logical context, but it is not enough when deserializing it on a +different network host: for that it would need to include the system’s remote +transport address. + +Scala +: @@snip [SerializationDocSpec.scala](/akka-docs/src/test/scala/docs/serialization/SerializationDocSpec.scala) { #external-address-default } + +Java +: @@snip [SerializationDocTest.java](/akka-docs/src/test/java/jdocs/serialization/SerializationDocTest.java) { #external-address-default } + +@@@ note + +`ActorPath.toSerializationFormatWithAddress` differs from `toString` if the +address does not already have `host` and `port` components, i.e. it only +inserts address information for local addresses. + +`toSerializationFormatWithAddress` also adds the unique id of the actor, which will +change when the actor is stopped and then created again with the same name. +Sending messages to a reference pointing the old actor will not be delivered +to the new actor. If you don't want this behavior, e.g. in case of long term +storage of the reference, you can use `toStringWithAddress`, which doesn't +include the unique id. + +@@@ + +There is also a default remote address which is the one used by cluster support +(and typical systems have just this one); you can get it like this: + +Scala +: @@snip [SerializationDocSpec.scala](/akka-docs/src/test/scala/docs/serialization/SerializationDocSpec.scala) { #external-address-default } + +Java +: @@snip [SerializationDocTest.java](/akka-docs/src/test/java/jdocs/serialization/SerializationDocTest.java) { #external-address-default } + diff --git a/akka-docs/src/main/paradox/serialization.md b/akka-docs/src/main/paradox/serialization.md index e9bb52bb3c..8086015cc4 100644 --- a/akka-docs/src/main/paradox/serialization.md +++ b/akka-docs/src/main/paradox/serialization.md @@ -103,6 +103,14 @@ It is important to use the serializer identifier in this way to support rolling consisting of the bytes, the serializer id, and the manifest should always be transferred or stored together so that they can be deserialized with different `serialization-bindings` configuration. +The `SerializationExtension` is a Classic `Extension` but it can be used with an `akka.actor.typed.ActorSystem` like this: + +Scala +: @@snip [SerializationDocSpec.scala](/akka-docs/src/test/scala/docs/serialization/SerializationDocSpec.scala) { #programmatic-typed } + +Java +: @@snip [SerializationDocTest.java](/akka-docs/src/test/java/jdocs/serialization/SerializationDocTest.java) { #programmatic-typed } + ## Customization The first code snippet on this page contains a configuration file that references a custom serializer `docs.serialization.MyOwnSerializer`. How would we go about creating such a custom serializer? @@ -171,64 +179,22 @@ transport. Artery TCP handles all deserialization exceptions as transient proble ### Serializing ActorRefs -All ActorRefs are serializable using JavaSerializer, but in case you are writing your -own serializer, you might want to know how to serialize and deserialize them properly. -In the general case, the local address to be used depends on the type of remote -address which shall be the recipient of the serialized information. Use -`Serialization.serializedActorPath(actorRef)` like this: +Actor references are typically included in the messages. +All ActorRefs are serializable when using @ref:[Serialization with Jackson](serialization-jackson.md), +but in case you are writing your own serializer, you might want to know how to serialize and deserialize them properly. + +To serialize actor references to/from string representation you would use the @apidoc[akka.actor.typed.ActorRefResolver]. + +For example here's how a serializer could look for `Ping` and `Pong` messages: Scala -: @@snip [SerializationDocSpec.scala](/akka-docs/src/test/scala/docs/serialization/SerializationDocSpec.scala) { #imports } +: @@snip [PingSerializer.scala](/akka-cluster-typed/src/test/scala/docs/akka/cluster/typed/PingSerializer.scala) { #serializer } Java -: @@snip [SerializationDocTest.java](/akka-docs/src/test/java/jdocs/serialization/SerializationDocTest.java) { #imports } +: @@snip [PingSerializerExampleTest.java](/akka-cluster-typed/src/test/java/jdocs/akka/cluster/typed/PingSerializerExampleTest.java) { #serializer } - -Scala -: @@snip [SerializationDocSpec.scala](/akka-docs/src/test/scala/docs/serialization/SerializationDocSpec.scala) { #actorref-serializer } - -Java -: @@snip [SerializationDocTest.java](/akka-docs/src/test/java/jdocs/serialization/SerializationDocTest.java) { #actorref-serializer } - -This assumes that serialization happens in the context of sending a message -through the remote transport. There are other uses of serialization, though, -e.g. storing actor references outside of an actor application (database, etc.). -In this case, it is important to keep in mind that the -address part of an actor’s path determines how that actor is communicated with. -Storing a local actor path might be the right choice if the retrieval happens -in the same logical context, but it is not enough when deserializing it on a -different network host: for that it would need to include the system’s remote -transport address. - -Scala -: @@snip [SerializationDocSpec.scala](/akka-docs/src/test/scala/docs/serialization/SerializationDocSpec.scala) { #external-address-default } - -Java -: @@snip [SerializationDocTest.java](/akka-docs/src/test/java/jdocs/serialization/SerializationDocTest.java) { #external-address-default } - -@@@ note - -`ActorPath.toSerializationFormatWithAddress` differs from `toString` if the -address does not already have `host` and `port` components, i.e. it only -inserts address information for local addresses. - -`toSerializationFormatWithAddress` also adds the unique id of the actor, which will -change when the actor is stopped and then created again with the same name. -Sending messages to a reference pointing the old actor will not be delivered -to the new actor. If you don't want this behavior, e.g. in case of long term -storage of the reference, you can use `toStringWithAddress`, which doesn't -include the unique id. - -@@@ - -There is also a default remote address which is the one used by cluster support -(and typical systems have just this one); you can get it like this: - -Scala -: @@snip [SerializationDocSpec.scala](/akka-docs/src/test/scala/docs/serialization/SerializationDocSpec.scala) { #external-address-default } - -Java -: @@snip [SerializationDocTest.java](/akka-docs/src/test/java/jdocs/serialization/SerializationDocTest.java) { #external-address-default } +Serialization of Classic `ActorRef` is described in @ref:[Classic Serialization](serialization-classic.md#serializing-actorrefs). +Classic and Typed actor references have the same serialization format so they can be interchanged. ### Deep serialization of Actors @@ -308,4 +274,4 @@ It must still be possible to deserialize the events that were stored with the ol * [Akka-kryo by Roman Levenstein](https://github.com/romix/akka-kryo-serialization) -* [Twitter Chill Scala extensions for Kryo (based on Akka Version 2.3.x but due to backwards compatibility of the Serializer Interface this extension also works with 2.4.x)](https://github.com/twitter/chill) +* [Twitter Chill Scala extensions for Kryo](https://github.com/twitter/chill) diff --git a/akka-docs/src/main/paradox/typed/actor-discovery.md b/akka-docs/src/main/paradox/typed/actor-discovery.md index ab6e1aa319..e68d1f3dcf 100644 --- a/akka-docs/src/main/paradox/typed/actor-discovery.md +++ b/akka-docs/src/main/paradox/typed/actor-discovery.md @@ -84,4 +84,4 @@ registered actors that are reachable. The full set of actors, including unreacha @scala[`Listing.allServiceInstances`]@java[`Listing.getAllServiceInstances`]. One important difference from local only receptions are the serialization concerns, all messages sent to and back from -an actor on another node must be serializable, see @ref:[clustering](cluster.md#serialization). +an actor on another node must be serializable, see @ref:[serialization](../serialization.md). diff --git a/akka-docs/src/main/paradox/typed/cluster.md b/akka-docs/src/main/paradox/typed/cluster.md index 4281a99156..ab3163e718 100644 --- a/akka-docs/src/main/paradox/typed/cluster.md +++ b/akka-docs/src/main/paradox/typed/cluster.md @@ -10,6 +10,14 @@ For specific documentation topics see: * @ref:[Rolling Updates](../additional/rolling-updates.md) * @ref:[Operating, Managing, Observability](../additional/operations.md) +@@@ note + +You have to enable @ref:[serialization](../serialization.md) to send messages between ActorSystems in the Cluster. +@ref:[Serialization with Jackson](../serialization-jackson.md) is a good choice in many cases, and our +recommendation if you don't have other preferences or constraints. + +@@@ + ## Dependency To use Akka Cluster add the following dependency in your project: @@ -20,6 +28,19 @@ To use Akka Cluster add the following dependency in your project: version=$akka.version$ } +## Cluster samples + +To see what using Akka Cluster looks like in practice, see the +@java[@extref[Cluster example project](samples:akka-samples-cluster-java)] +@scala[@extref[Cluster example project](samples:akka-samples-cluster-scala)]. +This project contains samples illustrating different features, such as +subscribing to cluster membership events, sending messages to actors running on nodes in the cluster, +and using Cluster aware routers. + +The easiest way to run this example yourself is to try the +@scala[@extref[Akka Cluster Sample with Scala](samples:akka-samples-cluster-scala)]@java[@extref[Akka Cluster Sample with Java](samples:akka-samples-cluster-java)]. +It contains instructions on how to run the `SimpleClusterApp`. + ## Cluster API Extension The Cluster extension gives you access to management tasks such as @ref:[Joining, Leaving and Downing](cluster-membership.md#user-actions) @@ -291,27 +312,6 @@ be necessary to set the node’s status to `Down` in order to complete the remov see [Split Brain Resolver](http://developer.lightbend.com/docs/akka-commercial-addons/current/split-brain-resolver.html), part of the [Lightbend Reactive Platform](http://www.lightbend.com/platform). -## Serialization - -Enable @ref:[serialization](../serialization.md) to send events between ActorSystems. -@ref:[Serialization with Jackson](../serialization-jackson.md) is a good choice in many cases, and our -recommendation if you don't have other preferences or constraints. - -Actor references are typically included in the messages, since there is no `sender`. -To serialize actor references to/from string representation you would use the `ActorRefResolver`. -For example here's how a serializer could look for `Ping` and `Pong` messages: - -Scala -: @@snip [PingSerializer.scala](/akka-cluster-typed/src/test/scala/docs/akka/cluster/typed/PingSerializer.scala) { #serializer } - -Java -: @@snip [PingSerializerExampleTest.java](/akka-cluster-typed/src/test/java/jdocs/akka/cluster/typed/PingSerializerExampleTest.java) { #serializer } - -You can look at the -@java[@extref[Cluster example project](samples:akka-samples-cluster-java)] -@scala[@extref[Cluster example project](samples:akka-samples-cluster-scala)] -to see what this looks like in practice. - ## Node Roles Not all nodes of a cluster need to perform the same function: there might be one sub-set which runs the web front-end, diff --git a/akka-docs/src/main/paradox/typed/persistence.md b/akka-docs/src/main/paradox/typed/persistence.md index 5b7ce1f8ef..e6a017d797 100644 --- a/akka-docs/src/main/paradox/typed/persistence.md +++ b/akka-docs/src/main/paradox/typed/persistence.md @@ -330,9 +330,9 @@ command or the reply will be sent later, perhaps after some asynchronous interac ## Serialization -The same @ref:[serialization](../serialization.md) mechanism as for classic -actors is also used in Akka Typed, also for persistent actors. When picking serialization solution for the events -you should also consider that it must be possible read old events when the application has evolved. +The same @ref:[serialization](../serialization.md) mechanism as for actor messages is also used for persistent actors. +When picking serialization solution for the events you should also consider that it must be possible read old events +when the application has evolved. Strategies for that can be found in the @ref:[schema evolution](../persistence-schema-evolution.md). You need to enable @ref:[serialization](../serialization.md) for your commands (messages), events, and state (snapshot). diff --git a/akka-docs/src/test/java/jdocs/serialization/SerializationDocTest.java b/akka-docs/src/test/java/jdocs/serialization/SerializationDocTest.java index 638f8b10bf..e16814d780 100644 --- a/akka-docs/src/test/java/jdocs/serialization/SerializationDocTest.java +++ b/akka-docs/src/test/java/jdocs/serialization/SerializationDocTest.java @@ -6,6 +6,7 @@ package jdocs.serialization; import java.io.UnsupportedEncodingException; +import akka.actor.typed.javadsl.Behaviors; import akka.cluster.Cluster; import akka.testkit.javadsl.TestKit; import org.junit.Test; @@ -188,4 +189,15 @@ public class SerializationDocTest { TestKit.shutdownActorSystem(system); } + + public void demonstrateTheProgrammaticAPITyped() { + // #programmatic-typed + akka.actor.typed.ActorSystem system = + akka.actor.typed.ActorSystem.create(Behaviors.empty(), "example"); + + // Get the Serialization Extension + Serialization serialization = + SerializationExtension.get(akka.actor.typed.javadsl.Adapter.toClassic(system)); + // #programmatic-typed + } } diff --git a/akka-docs/src/test/scala/docs/serialization/SerializationDocSpec.scala b/akka-docs/src/test/scala/docs/serialization/SerializationDocSpec.scala index c8535ef542..1b4994f267 100644 --- a/akka-docs/src/test/scala/docs/serialization/SerializationDocSpec.scala +++ b/akka-docs/src/test/scala/docs/serialization/SerializationDocSpec.scala @@ -6,6 +6,7 @@ package docs.serialization { //#imports import akka.actor._ + import akka.actor.typed.scaladsl.Behaviors import akka.cluster.Cluster import akka.serialization._ @@ -210,6 +211,18 @@ package docs.serialization { shutdown(system) } + def demonstrateTypedActorSystem(): Unit = { + //#programmatic-typed + import akka.actor.typed.ActorSystem + import akka.actor.typed.scaladsl.adapter._ + + val system = ActorSystem(Behaviors.empty, "example") + + // Get the Serialization Extension + val serialization = SerializationExtension(system.toClassic) + //#programmatic-typed + } + def demonstrateSerializationOfActorRefs(): Unit = { val theActorRef: ActorRef = system.deadLetters val extendedSystem: ExtendedActorSystem = system.asInstanceOf[ExtendedActorSystem]