General concepts docs ported to typed (#27765)

This commit is contained in:
Johan Andrén 2019-09-27 09:50:34 +02:00 committed by GitHub
parent ea74f905ea
commit 0719de035b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 814 additions and 624 deletions

View file

@ -0,0 +1,141 @@
/*
* Copyright (C) 2009-2019 Lightbend Inc. <https://www.lightbend.com>
*/
package jdocs.actor.typed;
import akka.actor.typed.ActorRef;
import akka.actor.typed.Behavior;
import akka.actor.typed.javadsl.AbstractBehavior;
import akka.actor.typed.javadsl.ActorContext;
import akka.actor.typed.javadsl.Receive;
import akka.actor.typed.javadsl.AskPattern;
import java.time.Duration;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
interface SharedMutableStateDocTest {
static CompletableFuture<String> expensiveCalculation() {
throw new UnsupportedOperationException("just a sample signature");
}
class Query {
public final ActorRef<String> replyTo;
public Query(ActorRef<String> replyTo) {
this.replyTo = replyTo;
}
}
// #mutable-state
class MyActor extends AbstractBehavior<MyActor.Command> {
interface Command {}
class Message implements Command {
public final ActorRef<Object> otherActor;
public Message(ActorRef<Object> replyTo) {
this.otherActor = replyTo;
}
}
class UpdateState implements Command {
public final String newState;
public UpdateState(String newState) {
this.newState = newState;
}
}
private final ActorContext<Command> context;
private String state = "";
private Set<String> mySet = new HashSet<>();
public MyActor(ActorContext<Command> context) {
this.context = context;
}
@Override
public Receive<Command> createReceive() {
return newReceiveBuilder()
.onMessage(Message.class, this::onMessage)
.onMessage(UpdateState.class, this::onUpdateState)
.build();
}
private Behavior<Command> onMessage(Message message) {
// Very bad: shared mutable object allows
// the other actor to mutate your own state,
// or worse, you might get weird race conditions
message.otherActor.tell(mySet);
// Example of incorrect approach
// Very bad: shared mutable state will cause your
// application to break in weird ways
CompletableFuture.runAsync(
() -> {
state = "This will race";
});
// Example of incorrect approach
// Very bad: shared mutable state will cause your
// application to break in weird ways
expensiveCalculation()
.whenComplete(
(result, failure) -> {
if (result != null) state = "new state: " + result;
});
// Example of correct approach
// Turn the future result into a message that is sent to
// self when future completes
CompletableFuture<String> futureResult = expensiveCalculation();
context.pipeToSelf(
futureResult,
(result, failure) -> {
if (result != null) return new UpdateState(result);
else throw new RuntimeException(failure);
});
// Another example of incorrect approach
// mutating actor state from ask future callback
CompletionStage<String> response =
AskPattern.ask(
message.otherActor,
Query::new,
Duration.ofSeconds(3),
context.getSystem().scheduler());
response.whenComplete(
(result, failure) -> {
if (result != null) state = "new state: " + result;
});
// use context.ask instead, turns the completion
// into a message sent to self
context.ask(
String.class,
message.otherActor,
Duration.ofSeconds(3),
Query::new,
(result, failure) -> {
if (result != null) return new UpdateState(result);
else throw new RuntimeException(failure);
});
return this;
}
private Behavior<Command> onUpdateState(UpdateState command) {
// safe as long as `newState` is immutable, if it is mutable we'd need to
// make a defensive copy
this.state = command.newState;
return this;
}
}
// #mutable-state
}

View file

@ -1,28 +0,0 @@
/*
* Copyright (C) 2009-2019 Lightbend Inc. <https://www.lightbend.com>
*/
package jdocs.config;
import akka.actor.ActorSystem;
import com.typesafe.config.*;
public class ConfigDoc {
public ActorSystem createConfiguredSystem() {
// #java-custom-config
// make a Config with just your special setting
Config myConfig = ConfigFactory.parseString("something=somethingElse");
// load the normal config stack (system props,
// then application.conf, then reference.conf)
Config regularConfig = ConfigFactory.load();
// override regular stack with myConfig
Config combined = myConfig.withFallback(regularConfig);
// put the result in between the overrides
// (system props) and defaults again
Config complete = ConfigFactory.load(combined);
// create ActorSystem
ActorSystem system = ActorSystem.create("myname", complete);
// #java-custom-config
return system;
}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (C) 2009-2019 Lightbend Inc. <https://www.lightbend.com>
*/
package jdocs.config;
// #imports
import akka.actor.typed.ActorSystem;
import akka.actor.typed.Behavior;
import akka.actor.typed.javadsl.Behaviors;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
// #imports
import akka.actor.testkit.typed.javadsl.ActorTestKit;
public class ConfigDocTest {
private Behavior<Void> rootBehavior = Behaviors.empty();
public void customConfig() {
// #custom-config
Config customConf = ConfigFactory.parseString("akka.log-config-on-start = on");
// ConfigFactory.load sandwiches customConfig between default reference
// config and default overrides, and then resolves it.
ActorSystem<Void> system =
ActorSystem.create(rootBehavior, "MySystem", ConfigFactory.load(customConf));
// #custom-config
ActorTestKit.shutdown(system);
}
public void compileOnlyPrintConfig() {
// #dump-config
ActorSystem<Void> system = ActorSystem.create(rootBehavior, "MySystem");
system.logConfiguration();
// #dump-config
}
public void compileOnlySeparateApps() {
// #separate-apps
Config config = ConfigFactory.load();
ActorSystem<Void> app1 =
ActorSystem.create(rootBehavior, "MyApp1", config.getConfig("myapp1").withFallback(config));
ActorSystem<Void> app2 =
ActorSystem.create(
rootBehavior,
"MyApp2",
config.getConfig("myapp2").withOnlyPath("akka").withFallback(config));
// #separate-apps
}
public ActorSystem createConfiguredSystem() {
// #custom-config-2
// make a Config with just your special setting
Config myConfig = ConfigFactory.parseString("something=somethingElse");
// load the normal config stack (system props,
// then application.conf, then reference.conf)
Config regularConfig = ConfigFactory.load();
// override regular stack with myConfig
Config combined = myConfig.withFallback(regularConfig);
// put the result in between the overrides
// (system props) and defaults again
Config complete = ConfigFactory.load(combined);
// create ActorSystem
ActorSystem system = ActorSystem.create(rootBehavior, "myname", complete);
// #custom-config-2
return system;
}
}