Typed docs for sharding and singleton (#24364)

This commit is contained in:
Christopher Batey 2018-01-22 13:47:18 +00:00 committed by GitHub
parent f32cd63dc1
commit 719f0fb672
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 287 additions and 11 deletions

View file

@ -283,7 +283,7 @@ final class AdaptedClusterShardingImpl(system: ActorSystem[_]) extends ClusterSh
}
@DoNotInherit
sealed trait ClusterSharding extends Extension {
sealed abstract class ClusterSharding extends Extension {
/**
* Spawn a shard region or a proxy depending on if the settings require role and if this node has such a role.

View file

@ -0,0 +1,82 @@
package jdoc.akka.cluster.sharding.typed;
import akka.actor.typed.ActorRef;
import akka.actor.typed.ActorSystem;
import akka.actor.typed.Behavior;
import akka.actor.typed.Props;
import akka.actor.typed.javadsl.Behaviors;
import akka.cluster.sharding.typed.ClusterSharding;
import akka.cluster.sharding.typed.*;
import akka.cluster.typed.ClusterSingleton;
import akka.cluster.typed.ClusterSingletonSettings;
public class ShardingCompileOnlyTest {
//#counter
interface CounterCommand {}
public static class Increment implements CounterCommand { }
public static class GoodByeCounter implements CounterCommand { }
public static class GetValue implements CounterCommand {
private final ActorRef<Integer> replyTo;
public GetValue(ActorRef<Integer> replyTo) {
this.replyTo = replyTo;
}
}
public static Behavior<CounterCommand> counter(Integer value) {
return Behaviors.immutable(CounterCommand.class)
.onMessage(Increment.class, (ctx, msg) -> {
return counter(value + 1);
})
.onMessage(GetValue.class, (ctx, msg) -> {
msg.replyTo.tell(value);
return Behaviors.same();
})
.build();
}
//#counter
public static void example() {
ActorSystem system = ActorSystem.create(
Behaviors.empty(), "ShardingExample"
);
//#sharding-extension
ClusterSharding sharding = ClusterSharding.get(system);
//#sharding-extension
//#spawn
EntityTypeKey<CounterCommand> typeKey = EntityTypeKey.create(CounterCommand.class, "Counter");
ActorRef<ShardingEnvelope<CounterCommand>> shardRegion = sharding.spawn(
counter(0),
Props.empty(),
typeKey,
ClusterShardingSettings.create(system),
10,
new GoodByeCounter());
//#spawn
//#send
EntityRef<CounterCommand> counterOne = sharding.entityRefFor(typeKey, "counter-`");
counterOne.tell(new Increment());
shardRegion.tell(new ShardingEnvelope<>("counter-1", new Increment()));
//#send
//#singleton
ClusterSingleton singleton = ClusterSingleton.get(system);
// Start if needed and provide a proxy to a named singleton
ActorRef<CounterCommand> proxy = singleton.spawn(
counter(0),
"GlobalCounter",
Props.empty(),
ClusterSingletonSettings.create(system),
new GoodByeCounter()
);
proxy.tell(new Increment());
//#singleton
}
}

View file

@ -0,0 +1,81 @@
package doc.akka.cluster.sharding.typed
import akka.actor.typed.{ ActorRef, ActorSystem, Behavior, Props }
import akka.actor.typed.scaladsl.Behaviors
import akka.cluster.typed.{ ClusterSingleton, ClusterSingletonSettings }
import docs.akka.persistence.typed.InDepthPersistentBehaviorSpec
import docs.akka.persistence.typed.InDepthPersistentBehaviorSpec.{ BlogCommand, PassivatePost }
object ShardingCompileOnlySpec {
val system = ActorSystem(Behaviors.empty, "Sharding")
//#sharding-extension
import akka.cluster.sharding.typed._
val sharding = ClusterSharding(system)
//#sharding-extension
//#counter
trait CounterCommand
case object Increment extends CounterCommand
final case class GetValue(replyTo: ActorRef[Int]) extends CounterCommand
case object GoodByeCounter extends CounterCommand
def counter(value: Int): Behavior[CounterCommand] = Behaviors.immutable[CounterCommand] {
case (ctx, Increment)
counter(value + 1)
case (ctx, GetValue(replyTo))
replyTo ! value
Behaviors.same
}
//#counter
//#spawn
val TypeKey = EntityTypeKey[CounterCommand]("Counter")
// if a extractor is defined then the type would be ActorRef[BasicCommand]
val shardRegion: ActorRef[ShardingEnvelope[CounterCommand]] = sharding.spawn[CounterCommand](
behavior = counter(0),
props = Props.empty,
typeKey = TypeKey,
settings = ClusterShardingSettings(system),
maxNumberOfShards = 10,
handOffStopMessage = GoodByeCounter)
//#spawn
//#send
// With an EntityRef
val counterOne: EntityRef[CounterCommand] = sharding.entityRefFor(TypeKey, "counter-1")
counterOne ! Increment
// Entity id is specified via an `ShardingEnvelope`
shardRegion ! ShardingEnvelope("counter-1", Increment)
//#send
//#persistence
val ShardingTypeName = EntityTypeKey[BlogCommand]("BlogPost")
ClusterSharding(system).spawn[BlogCommand](
behavior = InDepthPersistentBehaviorSpec.behavior,
props = Props.empty,
typeKey = ShardingTypeName,
settings = ClusterShardingSettings(system),
maxNumberOfShards = 10,
handOffStopMessage = PassivatePost)
//#persistence
// as a singleton
//#singleton
val singletonManager = ClusterSingleton(system)
// Start if needed and provide a proxy to a named singleton
val proxy: ActorRef[CounterCommand] = singletonManager.spawn(
behavior = counter(0),
"GlobalCounter",
Props.empty,
ClusterSingletonSettings(system),
terminationMessage = GoodByeCounter
)
proxy ! Increment
//#singleton
}

View file

@ -8,7 +8,6 @@ import akka.annotation.{ DoNotInherit, InternalApi }
import akka.cluster.ClusterSettings.DataCenter
import akka.cluster.singleton.{ ClusterSingletonProxySettings, ClusterSingletonManagerSettings UntypedClusterSingletonManagerSettings }
import akka.cluster.typed.internal.AdaptedClusterSingletonImpl
import akka.actor.typed.internal.adapter.ActorSystemAdapter
import akka.actor.typed.{ ActorRef, ActorSystem, Behavior, Extension, ExtensionId, Props }
import com.typesafe.config.Config
import scala.concurrent.duration._
@ -20,6 +19,11 @@ object ClusterSingletonSettings {
system: ActorSystem[_]
): ClusterSingletonSettings = fromConfig(system.settings.config.getConfig("akka.cluster"))
/**
* Java API
*/
def create(system: ActorSystem[_]): ClusterSingletonSettings = apply(system)
def fromConfig(
config: Config
): ClusterSingletonSettings = {
@ -115,7 +119,7 @@ private[akka] object ClusterSingletonImpl {
* Not intended for user extension.
*/
@DoNotInherit
trait ClusterSingleton extends Extension {
abstract class ClusterSingleton extends Extension {
/**
* Start if needed and provide a proxy to a named singleton

View file

@ -1,4 +1,4 @@
# Sharding
# Cluster Sharding
@@@ warning
@ -9,7 +9,7 @@ This module is currently marked as @ref:[may change](common/may-change.md) in th
@@@
To use the testkit add the following dependency:
To use cluster sharding add the following dependency:
@@dependency [sbt,Maven,Gradle] {
group=com.typesafe.akka
@ -17,5 +17,60 @@ To use the testkit add the following dependency:
version=$akka.version$
}
For an introduction to Akka Cluster concepts see [Cluster Specification]. This documentation shows how to use the typed
Cluster API.
For an introduction to Sharding concepts see @ref:[Cluster Sharding](cluster-sharding.md). This documentation shows how to use the typed
Cluster Sharding API.
## Basic example
Sharding is accessed via the `ClusterSharding` extension
Scala
: @@snip [ShardingCompileOnlySpec.scala]($akka$/akka-cluster-sharding-typed/src/test/scala/doc/akka/cluster/sharding/typed/ShardingCompileOnlySpec.scala) { #sharding-extension }
Java
: @@snip [ShardingCompileOnlyTest.java]($akka$/akka-cluster-sharding-typed/src/test/java/jdoc/akka/cluster/sharding/typed/ShardingCompileOnlyTest.java) { #sharding-extension }
It is common for sharding to be used with persistence however any Behavior can be used with sharding e.g. a basic counter:
Scala
: @@snip [ShardingCompileOnlySpec.scala]($akka$/akka-cluster-sharding-typed/src/test/scala/doc/akka/cluster/sharding/typed/ShardingCompileOnlySpec.scala) { #counter }
Java
: @@snip [ShardingCompileOnlyTest.java]($akka$/akka-cluster-sharding-typed/src/test/java/jdoc/akka/cluster/sharding/typed/ShardingCompileOnlyTest.java) { #counter }
Each Entity type has a key that is then used to retrieve an EntityRef for a given entity identifier.
Scala
: @@snip [ShardingCompileOnlySpec.scala]($akka$/akka-cluster-sharding-typed/src/test/scala/doc/akka/cluster/sharding/typed/ShardingCompileOnlySpec.scala) { #spawn }
Java
: @@snip [ShardingCompileOnlyTest.java]($akka$/akka-cluster-sharding-typed/src/test/java/jdoc/akka/cluster/sharding/typed/ShardingCompileOnlyTest.java) { #spawn }
Messages to a specific entity are then sent via an EntityRef.
It is also possible to wrap methods in a `ShardingEnvelop` or define extractor functions and send messages directly to the shard region.
Scala
: @@snip [ShardingCompileOnlySpec.scala]($akka$/akka-cluster-sharding-typed/src/test/scala/doc/akka/cluster/sharding/typed/ShardingCompileOnlySpec.scala) { #send }
Java
: @@snip [ShardingCompileOnlyTest.java]($akka$/akka-cluster-sharding-typed/src/test/java/jdoc/akka/cluster/sharding/typed/ShardingCompileOnlyTest.java) { #send }
## Persistence example
When using sharding entities can be moved to different nodes in the cluster. Persistence can be used to recover the state of
an actor after it has moved. Currently Akka typed only has a Scala API for persistence, you can track the progress of the
Java API [here](https://github.com/akka/akka/issues/24193).
Taking the larger example from the @ref:[persistence documentation](persistence-typed.md#larger-example) and making it into
a sharded entity is the same as for a non persistent behavior. The behavior:
Scala
: @@snip [InDepthPersistentBehaviorSpec.scala]($akka$/akka-persistence-typed/src/test/scala/docs/akka/persistence/typed/InDepthPersistentBehaviorSpec.scala) { #behavior }
To create the entity:
Scala
: @@snip [ShardingCompileOnlySpec.scala]($akka$/akka-cluster-sharding-typed/src/test/scala/doc/akka/cluster/sharding/typed/ShardingCompileOnlySpec.scala) { #persistence }
Sending messages to entities is the same as the example above. The only difference is ow when an entity is moved the state will be restored.
See @ref:[persistence](persistence-typed.md) for more details.

View file

@ -0,0 +1,55 @@
# Cluster Singleton
@@@ warning
This module is currently marked as @ref:[may change](common/may-change.md) in the sense
of being the subject of active research. This means that API or semantics can
change without warning or deprecation period and it is not recommended to use
this module in production just yet—you have been warned.
@@@
To use the cluster singletons add the following dependency:
@@dependency [sbt,Maven,Gradle] {
group=com.typesafe.akka
artifact=akka-cluster-typed_2.12
version=$akka.version$
}
For some use cases it is convenient and sometimes also mandatory to ensure that
you have exactly one actor of a certain type running somewhere in the cluster.
Some examples:
* single point of responsibility for certain cluster-wide consistent decisions, or
coordination of actions across the cluster system
* single entry point to an external system
* single master, many workers
* centralized naming service, or routing logic
Using a singleton should not be the first design choice. It has several drawbacks,
such as single-point of bottleneck. Single-point of failure is also a relevant concern,
but for some cases this feature takes care of that by making sure that another singleton
instance will eventually be started.
# Example
Any `Behavior` can be run as a singleton. E.g. a basic counter:
Scala
: @@snip [ShardingCompileOnlySpec.scala]($akka$/akka-cluster-sharding-typed/src/test/scala/doc/akka/cluster/sharding/typed/ShardingCompileOnlySpec.scala) { #sharding-extension }
Java
: @@snip [ShardingCompileOnlyTest.java]($akka$/akka-cluster-sharding-typed/src/test/java/jdoc/akka/cluster/sharding/typed/ShardingCompileOnlyTest.java) { #sharding-extension }
Then on every node in the cluster, or every node with a given role, use the `ClusterSingleton` extension
to spawn the singleton. Only a single instance will run in the cluster:
Scala
: @@snip [ShardingCompileOnlySpec.scala]($akka$/akka-cluster-sharding-typed/src/test/scala/doc/akka/cluster/sharding/typed/ShardingCompileOnlySpec.scala) { #singleton }
Java
: @@snip [ShardingCompileOnlyTest.java]($akka$/akka-cluster-sharding-typed/src/test/java/jdoc/akka/cluster/sharding/typed/ShardingCompileOnlyTest.java) { #singleton }

View file

@ -11,6 +11,7 @@
* [fault-tolerance](fault-tolerance-typed.md)
* [actor-discovery](actor-discovery-typed.md)
* [cluster](cluster-typed.md)
* [cluster-singleton](cluster-singleton-typed.md)
* [cluster-sharding](cluster-sharding-typed.md)
* [persistence](persistence-typed.md)
* [testing](testing-typed.md)

View file

@ -125,6 +125,3 @@ object InDepthPersistentBehaviorSpec {
//#behavior
}
class InDepthPersistentBehaviorSpec {
}

View file

@ -415,7 +415,8 @@ lazy val clusterShardingTyped = akkaModule("akka-cluster-sharding-typed")
clusterSharding,
testkit % "test->test",
typedTestkit % "test->test",
actorTypedTests % "test->test"
actorTypedTests % "test->test",
persistenceTyped % "test->test"
)
.settings(AkkaBuild.mayChangeSettings)
.settings(AutomaticModuleName.settings("akka.cluster.sharding.typed"))