pekko/akka-cluster-sharding/src/test/java/akka/cluster/sharding/ClusterShardingTest.java

244 lines
7 KiB
Java
Raw Normal View History

/**
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
*/
2015-04-27 14:48:28 +02:00
package akka.cluster.sharding;
import static java.util.concurrent.TimeUnit.SECONDS;
import scala.concurrent.duration.Duration;
import akka.actor.AbstractActor;
import akka.actor.ActorInitializationException;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.OneForOneStrategy;
import akka.actor.PoisonPill;
import akka.actor.Props;
import akka.actor.SupervisorStrategy;
import akka.actor.Terminated;
import akka.actor.ReceiveTimeout;
import akka.actor.UntypedActor;
import akka.japi.Procedure;
import akka.japi.Option;
!per persistAsync Breaks binary compatibility because adding new methods to Eventsourced trait. Since akka-persistence is experimental this is ok, yet source-level compatibility has been perserved thankfuly :-) Deprecates: * Rename of EventsourcedProcessor -> PersistentActor * Processor -> suggest using PersistentActor * Migration guide for akka-persistence is separate, as wel'll deprecate in minor versions (its experimental) * Persistent as well as ConfirmablePersistent - since Processor, their main user will be removed soon. Other changes: * persistAsync works as expected when mixed with persist * A counter must be kept for pending stashing invocations * Uses only 1 shared list buffer for persit / persistAsync * Includes small benchmark * Docs also include info about not using Persistent() wrapper * uses java LinkedList, for best performance of append / head on persistInvocations; the get(0) is safe, because these msgs only come in response to persistInvocations * Renamed internal *MessagesSuccess/Failure messages because we kept small mistakes seeing the class "with s" and "without s" as the same * Updated everything that refered to EventsourcedProcessor to PersistentActor, including samples Refs #15227 Conflicts: akka-docs/rst/project/migration-guides.rst akka-persistence/src/main/scala/akka/persistence/JournalProtocol.scala akka-persistence/src/main/scala/akka/persistence/Persistent.scala akka-persistence/src/test/scala/akka/persistence/PersistentActorSpec.scala project/AkkaBuild.scala
2014-05-21 01:35:21 +02:00
import akka.persistence.UntypedPersistentActor;
import akka.cluster.Cluster;
import akka.japi.pf.DeciderBuilder;
import akka.japi.pf.ReceiveBuilder;
// Doc code, compile only
public class ClusterShardingTest {
ActorSystem system = null;
ActorRef getSelf() {
return null;
}
public void demonstrateUsage() {
//#counter-extractor
ShardRegion.MessageExtractor messageExtractor = new ShardRegion.MessageExtractor() {
@Override
public String entityId(Object message) {
if (message instanceof Counter.EntityEnvelope)
return String.valueOf(((Counter.EntityEnvelope) message).id);
else if (message instanceof Counter.Get)
return String.valueOf(((Counter.Get) message).counterId);
else
return null;
}
@Override
public Object entityMessage(Object message) {
if (message instanceof Counter.EntityEnvelope)
return ((Counter.EntityEnvelope) message).payload;
else
return message;
}
@Override
public String shardId(Object message) {
2014-10-27 10:52:34 +01:00
int numberOfShards = 100;
if (message instanceof Counter.EntityEnvelope) {
long id = ((Counter.EntityEnvelope) message).id;
2014-10-27 10:52:34 +01:00
return String.valueOf(id % numberOfShards);
} else if (message instanceof Counter.Get) {
long id = ((Counter.Get) message).counterId;
2014-10-27 10:52:34 +01:00
return String.valueOf(id % numberOfShards);
} else {
return null;
}
}
};
//#counter-extractor
//#counter-start
Option<String> roleOption = Option.none();
ClusterShardingSettings settings = ClusterShardingSettings.create(system);
ActorRef startedCounterRegion = ClusterSharding.get(system).start("Counter",
Props.create(Counter.class), settings, messageExtractor);
//#counter-start
//#counter-usage
ActorRef counterRegion = ClusterSharding.get(system).shardRegion("Counter");
2014-10-27 10:52:34 +01:00
counterRegion.tell(new Counter.Get(123), getSelf());
counterRegion.tell(new Counter.EntityEnvelope(123,
Counter.CounterOp.INCREMENT), getSelf());
2014-10-27 10:52:34 +01:00
counterRegion.tell(new Counter.Get(123), getSelf());
//#counter-usage
//#counter-supervisor-start
ClusterSharding.get(system).start("SupervisedCounter",
Props.create(CounterSupervisor.class), settings, messageExtractor);
//#counter-supervisor-start
}
static//#counter-actor
!per persistAsync Breaks binary compatibility because adding new methods to Eventsourced trait. Since akka-persistence is experimental this is ok, yet source-level compatibility has been perserved thankfuly :-) Deprecates: * Rename of EventsourcedProcessor -> PersistentActor * Processor -> suggest using PersistentActor * Migration guide for akka-persistence is separate, as wel'll deprecate in minor versions (its experimental) * Persistent as well as ConfirmablePersistent - since Processor, their main user will be removed soon. Other changes: * persistAsync works as expected when mixed with persist * A counter must be kept for pending stashing invocations * Uses only 1 shared list buffer for persit / persistAsync * Includes small benchmark * Docs also include info about not using Persistent() wrapper * uses java LinkedList, for best performance of append / head on persistInvocations; the get(0) is safe, because these msgs only come in response to persistInvocations * Renamed internal *MessagesSuccess/Failure messages because we kept small mistakes seeing the class "with s" and "without s" as the same * Updated everything that refered to EventsourcedProcessor to PersistentActor, including samples Refs #15227 Conflicts: akka-docs/rst/project/migration-guides.rst akka-persistence/src/main/scala/akka/persistence/JournalProtocol.scala akka-persistence/src/main/scala/akka/persistence/Persistent.scala akka-persistence/src/test/scala/akka/persistence/PersistentActorSpec.scala project/AkkaBuild.scala
2014-05-21 01:35:21 +02:00
public class Counter extends UntypedPersistentActor {
public static enum CounterOp {
INCREMENT, DECREMENT
}
public static class Get {
final public long counterId;
public Get(long counterId) {
this.counterId = counterId;
}
}
public static class EntityEnvelope {
final public long id;
final public Object payload;
public EntityEnvelope(long id, Object payload) {
this.id = id;
this.payload = payload;
}
}
public static class CounterChanged {
final public int delta;
public CounterChanged(int delta) {
this.delta = delta;
}
}
int count = 0;
// getSelf().path().name() is the entity identifier (utf-8 URL-encoded)
@Override
public String persistenceId() {
return "Counter-" + getSelf().path().name();
}
@Override
public void preStart() throws Exception {
super.preStart();
context().setReceiveTimeout(Duration.create(120, SECONDS));
}
void updateState(CounterChanged event) {
count += event.delta;
}
@Override
public void onReceiveRecover(Object msg) {
if (msg instanceof CounterChanged)
updateState((CounterChanged) msg);
else
unhandled(msg);
}
@Override
public void onReceiveCommand(Object msg) {
if (msg instanceof Get)
getSender().tell(count, getSelf());
else if (msg == CounterOp.INCREMENT)
persist(new CounterChanged(+1), new Procedure<CounterChanged>() {
public void apply(CounterChanged evt) {
updateState(evt);
}
});
else if (msg == CounterOp.DECREMENT)
persist(new CounterChanged(-1), new Procedure<CounterChanged>() {
public void apply(CounterChanged evt) {
updateState(evt);
}
});
else if (msg.equals(ReceiveTimeout.getInstance()))
getContext().parent().tell(
new ShardRegion.Passivate(PoisonPill.getInstance()), getSelf());
else
unhandled(msg);
}
}
//#counter-actor
static//#graceful-shutdown
public class IllustrateGracefulShutdown extends AbstractActor {
public IllustrateGracefulShutdown() {
final ActorSystem system = context().system();
final Cluster cluster = Cluster.get(system);
final ActorRef region = ClusterSharding.get(system).shardRegion("Entity");
receive(ReceiveBuilder.
match(String.class, s -> s.equals("leave"), s -> {
context().watch(region);
region.tell(ShardRegion.gracefulShutdownInstance(), self());
}).
match(Terminated.class, t -> t.actor().equals(region), t -> {
cluster.registerOnMemberRemoved(() ->
self().tell("member-removed", self()));
cluster.leave(cluster.selfAddress());
}).
match(String.class, s -> s.equals("member-removed"), s -> {
// Let singletons hand over gracefully before stopping the system
context().system().scheduler().scheduleOnce(Duration.create(10, SECONDS),
self(), "stop-system", context().dispatcher(), self());
}).
match(String.class, s -> s.equals("stop-system"), s -> {
system.terminate();
}).
build());
}
}
//#graceful-shutdown
static//#supervisor
public class CounterSupervisor extends UntypedActor {
private final ActorRef counter = getContext().actorOf(
Props.create(Counter.class), "theCounter");
private static final SupervisorStrategy strategy =
new OneForOneStrategy(DeciderBuilder.
match(IllegalArgumentException.class, e -> SupervisorStrategy.resume()).
match(ActorInitializationException.class, e -> SupervisorStrategy.stop()).
match(Exception.class, e -> SupervisorStrategy.restart()).
matchAny(o -> SupervisorStrategy.escalate()).build());
@Override
public SupervisorStrategy supervisorStrategy() {
return strategy;
}
@Override
public void onReceive(Object msg) {
counter.forward(msg, getContext());
}
}
//#supervisor
}