General concepts docs ported to typed (#27765)
This commit is contained in:
parent
ea74f905ea
commit
0719de035b
24 changed files with 814 additions and 624 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
70
akka-docs/src/test/java/jdocs/config/ConfigDocTest.java
Normal file
70
akka-docs/src/test/java/jdocs/config/ConfigDocTest.java
Normal 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;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue