2016-01-13 16:25:24 +01:00
|
|
|
/*
|
2019-01-02 18:55:26 +08:00
|
|
|
* Copyright (C) 2015-2019 Lightbend Inc. <https://www.lightbend.com>
|
2016-01-13 16:25:24 +01:00
|
|
|
*/
|
|
|
|
|
|
2017-03-16 09:30:00 +01:00
|
|
|
package jdocs.stream;
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2016-01-20 10:00:37 +02:00
|
|
|
import akka.NotUsed;
|
2016-01-13 16:25:24 +01:00
|
|
|
import akka.actor.*;
|
|
|
|
|
import akka.stream.*;
|
|
|
|
|
import akka.stream.javadsl.*;
|
|
|
|
|
import akka.testkit.TestProbe;
|
2017-03-17 03:02:47 +08:00
|
|
|
import akka.testkit.javadsl.TestKit;
|
2016-10-26 10:24:51 +02:00
|
|
|
import akka.util.Timeout;
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
import com.typesafe.config.Config;
|
|
|
|
|
import com.typesafe.config.ConfigFactory;
|
2017-03-16 09:30:00 +01:00
|
|
|
import jdocs.AbstractJavaTest;
|
|
|
|
|
import jdocs.stream.TwitterStreamQuickstartDocTest.Model.Author;
|
|
|
|
|
import jdocs.stream.TwitterStreamQuickstartDocTest.Model.Tweet;
|
2016-01-13 16:25:24 +01:00
|
|
|
import org.junit.AfterClass;
|
|
|
|
|
import org.junit.BeforeClass;
|
|
|
|
|
import org.junit.Test;
|
2017-03-16 09:30:00 +01:00
|
|
|
|
2018-05-22 18:27:54 +09:00
|
|
|
import java.time.Duration;
|
2016-01-13 16:25:24 +01:00
|
|
|
import java.util.Arrays;
|
|
|
|
|
import java.util.HashSet;
|
2017-03-17 03:02:47 +08:00
|
|
|
import java.util.List;
|
2016-01-13 16:25:24 +01:00
|
|
|
import java.util.Optional;
|
|
|
|
|
import java.util.Set;
|
2016-01-21 16:37:26 +01:00
|
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
|
|
import java.util.concurrent.CompletionStage;
|
|
|
|
|
import java.util.concurrent.Executor;
|
2016-10-26 10:24:51 +02:00
|
|
|
import java.util.concurrent.TimeUnit;
|
2016-01-13 16:25:24 +01:00
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
2018-12-06 22:40:43 +08:00
|
|
|
import static akka.pattern.Patterns.ask;
|
2017-03-16 09:30:00 +01:00
|
|
|
import static jdocs.stream.TwitterStreamQuickstartDocTest.Model.AKKA;
|
|
|
|
|
import static jdocs.stream.TwitterStreamQuickstartDocTest.Model.tweets;
|
2016-01-13 16:25:24 +01:00
|
|
|
import static junit.framework.TestCase.assertTrue;
|
|
|
|
|
|
2018-04-12 22:06:37 +09:00
|
|
|
@SuppressWarnings("ALL")
|
2016-02-11 16:39:25 +01:00
|
|
|
public class IntegrationDocTest extends AbstractJavaTest {
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
private static final SilenceSystemOut.System System = SilenceSystemOut.get();
|
|
|
|
|
|
|
|
|
|
static ActorSystem system;
|
2016-02-11 16:39:25 +01:00
|
|
|
static Materializer mat;
|
2016-10-26 10:24:51 +02:00
|
|
|
static ActorRef ref;
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
@BeforeClass
|
|
|
|
|
public static void setup() {
|
2019-01-12 04:00:53 +08:00
|
|
|
final Config config =
|
|
|
|
|
ConfigFactory.parseString(
|
|
|
|
|
""
|
|
|
|
|
+ "blocking-dispatcher { \n"
|
|
|
|
|
+ " executor = thread-pool-executor \n"
|
|
|
|
|
+ " thread-pool-executor { \n"
|
|
|
|
|
+ " core-pool-size-min = 10 \n"
|
|
|
|
|
+ " core-pool-size-max = 10 \n"
|
|
|
|
|
+ " } \n"
|
|
|
|
|
+ "} \n"
|
|
|
|
|
+ "akka.actor.default-mailbox.mailbox-type = akka.dispatch.UnboundedMailbox\n");
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
system = ActorSystem.create("ActorPublisherDocTest", config);
|
2016-02-11 16:39:25 +01:00
|
|
|
mat = ActorMaterializer.create(system);
|
2016-10-26 10:24:51 +02:00
|
|
|
ref = system.actorOf(Props.create(Translator.class));
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@AfterClass
|
|
|
|
|
public static void tearDown() {
|
2017-03-17 03:02:47 +08:00
|
|
|
TestKit.shutdownActorSystem(system);
|
2016-01-13 16:25:24 +01:00
|
|
|
system = null;
|
2016-02-11 16:39:25 +01:00
|
|
|
mat = null;
|
2016-10-26 10:24:51 +02:00
|
|
|
ref = null;
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class AddressSystem {
|
2019-01-12 04:00:53 +08:00
|
|
|
// #email-address-lookup
|
2016-01-21 16:37:26 +01:00
|
|
|
public CompletionStage<Optional<String>> lookupEmail(String handle)
|
2019-01-12 04:00:53 +08:00
|
|
|
// #email-address-lookup
|
|
|
|
|
{
|
2016-01-21 16:37:26 +01:00
|
|
|
return CompletableFuture.completedFuture(Optional.of(handle + "@somewhere.com"));
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #phone-lookup
|
2016-01-21 16:37:26 +01:00
|
|
|
public CompletionStage<Optional<String>> lookupPhoneNumber(String handle)
|
2019-01-12 04:00:53 +08:00
|
|
|
// #phone-lookup
|
|
|
|
|
{
|
2016-01-21 16:37:26 +01:00
|
|
|
return CompletableFuture.completedFuture(Optional.of("" + handle.hashCode()));
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class AddressSystem2 {
|
2019-01-12 04:00:53 +08:00
|
|
|
// #email-address-lookup2
|
2016-01-21 16:37:26 +01:00
|
|
|
public CompletionStage<String> lookupEmail(String handle)
|
2019-01-12 04:00:53 +08:00
|
|
|
// #email-address-lookup2
|
|
|
|
|
{
|
2016-01-21 16:37:26 +01:00
|
|
|
return CompletableFuture.completedFuture(handle + "@somewhere.com");
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static class Email {
|
|
|
|
|
public final String to;
|
|
|
|
|
public final String title;
|
|
|
|
|
public final String body;
|
|
|
|
|
|
|
|
|
|
public Email(String to, String title, String body) {
|
|
|
|
|
this.to = to;
|
|
|
|
|
this.title = title;
|
|
|
|
|
this.body = body;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean equals(Object o) {
|
|
|
|
|
if (this == o) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (o == null || getClass() != o.getClass()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Email email = (Email) o;
|
|
|
|
|
|
|
|
|
|
if (body != null ? !body.equals(email.body) : email.body != null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (title != null ? !title.equals(email.title) : email.title != null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (to != null ? !to.equals(email.to) : email.to != null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int hashCode() {
|
|
|
|
|
int result = to != null ? to.hashCode() : 0;
|
|
|
|
|
result = 31 * result + (title != null ? title.hashCode() : 0);
|
|
|
|
|
result = 31 * result + (body != null ? body.hashCode() : 0);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static class TextMessage {
|
|
|
|
|
public final String to;
|
|
|
|
|
public final String body;
|
|
|
|
|
|
|
|
|
|
TextMessage(String to, String body) {
|
|
|
|
|
this.to = to;
|
|
|
|
|
this.body = body;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean equals(Object o) {
|
|
|
|
|
if (this == o) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (o == null || getClass() != o.getClass()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TextMessage that = (TextMessage) o;
|
|
|
|
|
|
|
|
|
|
if (body != null ? !body.equals(that.body) : that.body != null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (to != null ? !to.equals(that.to) : that.to != null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int hashCode() {
|
|
|
|
|
int result = to != null ? to.hashCode() : 0;
|
|
|
|
|
result = 31 * result + (body != null ? body.hashCode() : 0);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static class EmailServer {
|
|
|
|
|
public final ActorRef probe;
|
|
|
|
|
|
|
|
|
|
public EmailServer(ActorRef probe) {
|
|
|
|
|
this.probe = probe;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #email-server-send
|
2016-01-21 16:37:26 +01:00
|
|
|
public CompletionStage<Email> send(Email email) {
|
2016-01-13 16:25:24 +01:00
|
|
|
// ...
|
2019-01-12 04:00:53 +08:00
|
|
|
// #email-server-send
|
2016-01-13 16:25:24 +01:00
|
|
|
probe.tell(email.to, ActorRef.noSender());
|
2016-01-21 16:37:26 +01:00
|
|
|
return CompletableFuture.completedFuture(email);
|
2019-01-12 04:00:53 +08:00
|
|
|
// #email-server-send
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
2019-01-12 04:00:53 +08:00
|
|
|
// #email-server-send
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static class SmsServer {
|
|
|
|
|
public final ActorRef probe;
|
|
|
|
|
|
|
|
|
|
public SmsServer(ActorRef probe) {
|
|
|
|
|
this.probe = probe;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #sms-server-send
|
2016-01-13 16:25:24 +01:00
|
|
|
public boolean send(TextMessage text) {
|
|
|
|
|
// ...
|
2019-01-12 04:00:53 +08:00
|
|
|
// #sms-server-send
|
2016-01-13 16:25:24 +01:00
|
|
|
probe.tell(text.to, ActorRef.noSender());
|
2019-01-12 04:00:53 +08:00
|
|
|
// #sms-server-send
|
2016-01-13 16:25:24 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
2019-01-12 04:00:53 +08:00
|
|
|
// #sms-server-send
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static class Save {
|
|
|
|
|
public final Tweet tweet;
|
|
|
|
|
|
|
|
|
|
Save(Tweet tweet) {
|
|
|
|
|
this.tweet = tweet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean equals(Object o) {
|
|
|
|
|
if (this == o) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (o == null || getClass() != o.getClass()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Save save = (Save) o;
|
|
|
|
|
|
|
|
|
|
if (tweet != null ? !tweet.equals(save.tweet) : save.tweet != null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int hashCode() {
|
|
|
|
|
return tweet != null ? tweet.hashCode() : 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-01-12 04:00:53 +08:00
|
|
|
|
2016-01-13 16:25:24 +01:00
|
|
|
static class SaveDone {
|
|
|
|
|
public static SaveDone INSTANCE = new SaveDone();
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
private SaveDone() {}
|
|
|
|
|
}
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
static class DatabaseService extends AbstractActor {
|
|
|
|
|
public final ActorRef probe;
|
|
|
|
|
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
public DatabaseService(ActorRef probe) {
|
2016-01-13 16:25:24 +01:00
|
|
|
this.probe = probe;
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
}
|
2018-01-14 00:21:00 +09:00
|
|
|
|
improve AbstractActor, #21717
* Receive class that wraps PartialFunction, to avoid
scary scala types
* move AbstractActorContext to AbstractActor.ActorContext
* converting docs, many, many UntypedActor
* removing UntypedActor docs
* add unit test for ReceiveBuilder
* MiMa filters
* consistent use of getContext(), self(), sender()
* rename cross references
* migration guide
* skip samples for now
* improve match type safetyi, add matchUnchecked
* the `? extends P` caused code like this to compile:
`match(String.class, (Integer i) -> {})`
* added matchUnchecked, since it can still be useful (um, convenient)
to be able to do:
`matchUnchecked(List.class, (List<String> list) -> {})`
* eleminate some scala.Option
* preRestart
* findChild
* ActorIdentity.getActorRef
2016-12-13 10:59:29 +01:00
|
|
|
@Override
|
|
|
|
|
public Receive createReceive() {
|
|
|
|
|
return receiveBuilder()
|
2019-01-12 04:00:53 +08:00
|
|
|
.match(
|
|
|
|
|
Save.class,
|
|
|
|
|
s -> {
|
|
|
|
|
probe.tell(s.tweet.author.handle, ActorRef.noSender());
|
|
|
|
|
getSender().tell(SaveDone.INSTANCE, getSelf());
|
|
|
|
|
})
|
|
|
|
|
.build();
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #sometimes-slow-service
|
2016-01-13 16:25:24 +01:00
|
|
|
static class SometimesSlowService {
|
2016-01-21 16:37:26 +01:00
|
|
|
private final Executor ec;
|
2018-01-14 00:21:00 +09:00
|
|
|
|
2016-01-21 16:37:26 +01:00
|
|
|
public SometimesSlowService(Executor ec) {
|
2016-01-13 16:25:24 +01:00
|
|
|
this.ec = ec;
|
|
|
|
|
}
|
2018-01-14 00:21:00 +09:00
|
|
|
|
2016-01-13 16:25:24 +01:00
|
|
|
private final AtomicInteger runningCount = new AtomicInteger();
|
|
|
|
|
|
2016-01-21 16:37:26 +01:00
|
|
|
public CompletionStage<String> convert(String s) {
|
2016-01-13 16:25:24 +01:00
|
|
|
System.out.println("running: " + s + "(" + runningCount.incrementAndGet() + ")");
|
2019-01-12 04:00:53 +08:00
|
|
|
return CompletableFuture.supplyAsync(
|
|
|
|
|
() -> {
|
|
|
|
|
if (!s.isEmpty() && Character.isLowerCase(s.charAt(0)))
|
|
|
|
|
try {
|
|
|
|
|
Thread.sleep(500);
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
try {
|
|
|
|
|
Thread.sleep(20);
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
}
|
|
|
|
|
System.out.println("completed: " + s + "(" + runningCount.decrementAndGet() + ")");
|
|
|
|
|
return s.toUpperCase();
|
|
|
|
|
},
|
|
|
|
|
ec);
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-01-12 04:00:53 +08:00
|
|
|
// #sometimes-slow-service
|
2018-01-14 00:21:00 +09:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #ask-actor
|
2017-02-04 11:51:30 +05:00
|
|
|
static class Translator extends AbstractActor {
|
2016-10-26 10:24:51 +02:00
|
|
|
@Override
|
2017-02-04 11:51:30 +05:00
|
|
|
public Receive createReceive() {
|
|
|
|
|
return receiveBuilder()
|
2019-01-12 04:00:53 +08:00
|
|
|
.match(
|
|
|
|
|
String.class,
|
|
|
|
|
word -> {
|
|
|
|
|
// ... process message
|
|
|
|
|
String reply = word.toUpperCase();
|
|
|
|
|
// reply to the ask
|
|
|
|
|
getSender().tell(reply, getSelf());
|
|
|
|
|
})
|
|
|
|
|
.build();
|
2016-10-26 10:24:51 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-01-12 04:00:53 +08:00
|
|
|
// #ask-actor
|
2018-01-14 00:21:00 +09:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #actorRefWithAck-actor
|
2018-05-15 11:52:07 +02:00
|
|
|
enum Ack {
|
|
|
|
|
INSTANCE;
|
|
|
|
|
}
|
2018-04-12 22:06:37 +09:00
|
|
|
|
|
|
|
|
static class StreamInitialized {}
|
2019-01-12 04:00:53 +08:00
|
|
|
|
2018-04-12 22:06:37 +09:00
|
|
|
static class StreamCompleted {}
|
2019-01-12 04:00:53 +08:00
|
|
|
|
2018-04-12 22:06:37 +09:00
|
|
|
static class StreamFailure {
|
|
|
|
|
private final Throwable cause;
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
public StreamFailure(Throwable cause) {
|
|
|
|
|
this.cause = cause;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Throwable getCause() {
|
|
|
|
|
return cause;
|
|
|
|
|
}
|
2018-04-12 22:06:37 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static class AckingReceiver extends AbstractLoggingActor {
|
|
|
|
|
|
2018-05-15 11:52:07 +02:00
|
|
|
private final ActorRef probe;
|
|
|
|
|
|
|
|
|
|
public AckingReceiver(ActorRef probe) {
|
|
|
|
|
this.probe = probe;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-12 22:06:37 +09:00
|
|
|
@Override
|
|
|
|
|
public Receive createReceive() {
|
|
|
|
|
return receiveBuilder()
|
2019-01-12 04:00:53 +08:00
|
|
|
.match(
|
|
|
|
|
StreamInitialized.class,
|
|
|
|
|
init -> {
|
|
|
|
|
log().info("Stream initialized");
|
|
|
|
|
probe.tell("Stream initialized", getSelf());
|
|
|
|
|
sender().tell(Ack.INSTANCE, self());
|
|
|
|
|
})
|
|
|
|
|
.match(
|
|
|
|
|
String.class,
|
|
|
|
|
element -> {
|
|
|
|
|
log().info("Received element: {}", element);
|
|
|
|
|
probe.tell(element, getSelf());
|
|
|
|
|
sender().tell(Ack.INSTANCE, self());
|
|
|
|
|
})
|
|
|
|
|
.match(
|
|
|
|
|
StreamCompleted.class,
|
|
|
|
|
completed -> {
|
|
|
|
|
log().info("Stream completed");
|
|
|
|
|
probe.tell("Stream completed", getSelf());
|
|
|
|
|
})
|
|
|
|
|
.match(
|
|
|
|
|
StreamFailure.class,
|
|
|
|
|
failed -> {
|
|
|
|
|
log().error(failed.getCause(), "Stream failed!");
|
|
|
|
|
probe.tell("Stream failed!", getSelf());
|
|
|
|
|
})
|
|
|
|
|
.build();
|
2018-04-12 22:06:37 +09:00
|
|
|
}
|
|
|
|
|
}
|
2019-01-12 04:00:53 +08:00
|
|
|
// #actorRefWithAck-actor
|
2018-04-12 22:06:37 +09:00
|
|
|
|
2016-10-26 10:24:51 +02:00
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
@Test
|
2018-01-14 00:21:00 +09:00
|
|
|
public void askStage() throws Exception {
|
2019-01-12 04:00:53 +08:00
|
|
|
// #ask
|
|
|
|
|
Source<String, NotUsed> words = Source.from(Arrays.asList("hello", "hi"));
|
2016-10-26 10:24:51 +02:00
|
|
|
Timeout askTimeout = Timeout.apply(5, TimeUnit.SECONDS);
|
2018-01-14 00:21:00 +09:00
|
|
|
|
2016-10-26 10:24:51 +02:00
|
|
|
words
|
2019-01-12 04:00:53 +08:00
|
|
|
.ask(5, ref, String.class, askTimeout)
|
|
|
|
|
// continue processing of the replies from the actor
|
|
|
|
|
.map(elem -> elem.toLowerCase())
|
|
|
|
|
.runWith(Sink.ignore(), mat);
|
|
|
|
|
// #ask
|
2016-10-26 10:24:51 +02:00
|
|
|
}
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2018-04-12 22:06:37 +09:00
|
|
|
@Test
|
|
|
|
|
public void actorRefWithAckExample() throws Exception {
|
2019-01-12 04:00:53 +08:00
|
|
|
// #actorRefWithAck
|
|
|
|
|
Source<String, NotUsed> words = Source.from(Arrays.asList("hello", "hi"));
|
2018-04-12 22:06:37 +09:00
|
|
|
|
2018-05-15 11:52:07 +02:00
|
|
|
final TestKit probe = new TestKit(system);
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
ActorRef receiver = system.actorOf(Props.create(AckingReceiver.class, probe.getRef()));
|
2018-04-12 22:06:37 +09:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
Sink<String, NotUsed> sink =
|
|
|
|
|
Sink.<String>actorRefWithAck(
|
|
|
|
|
receiver,
|
|
|
|
|
new StreamInitialized(),
|
|
|
|
|
Ack.INSTANCE,
|
|
|
|
|
new StreamCompleted(),
|
|
|
|
|
ex -> new StreamFailure(ex));
|
2018-04-12 22:06:37 +09:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
words.map(el -> el.toLowerCase()).runWith(sink, mat);
|
2018-05-15 11:52:07 +02:00
|
|
|
|
|
|
|
|
probe.expectMsg("Stream initialized");
|
|
|
|
|
probe.expectMsg("hello");
|
|
|
|
|
probe.expectMsg("hi");
|
|
|
|
|
probe.expectMsg("Stream completed");
|
2019-01-12 04:00:53 +08:00
|
|
|
// #actorRefWithAck
|
2018-04-12 22:06:37 +09:00
|
|
|
}
|
|
|
|
|
|
2016-01-13 16:25:24 +01:00
|
|
|
@Test
|
|
|
|
|
public void callingExternalServiceWithMapAsync() throws Exception {
|
2017-03-17 03:02:47 +08:00
|
|
|
new TestKit(system) {
|
2018-05-15 11:52:07 +02:00
|
|
|
final TestKit probe = new TestKit(system);
|
2016-01-13 16:25:24 +01:00
|
|
|
final AddressSystem addressSystem = new AddressSystem();
|
2018-05-15 11:52:07 +02:00
|
|
|
final EmailServer emailServer = new EmailServer(probe.getRef());
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
{
|
2019-01-12 04:00:53 +08:00
|
|
|
// #tweet-authors
|
|
|
|
|
final Source<Author, NotUsed> authors =
|
|
|
|
|
tweets.filter(t -> t.hashtags().contains(AKKA)).map(t -> t.author);
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #tweet-authors
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #email-addresses-mapAsync
|
|
|
|
|
final Source<String, NotUsed> emailAddresses =
|
|
|
|
|
authors
|
|
|
|
|
.mapAsync(4, author -> addressSystem.lookupEmail(author.handle))
|
|
|
|
|
.filter(o -> o.isPresent())
|
|
|
|
|
.map(o -> o.get());
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #email-addresses-mapAsync
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #send-emails
|
|
|
|
|
final RunnableGraph<NotUsed> sendEmails =
|
|
|
|
|
emailAddresses
|
|
|
|
|
.mapAsync(
|
|
|
|
|
4, address -> emailServer.send(new Email(address, "Akka", "I like your tweet")))
|
|
|
|
|
.to(Sink.ignore());
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
sendEmails.run(mat);
|
2019-01-12 04:00:53 +08:00
|
|
|
// #send-emails
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
probe.expectMsg("rolandkuhn@somewhere.com");
|
|
|
|
|
probe.expectMsg("patriknw@somewhere.com");
|
|
|
|
|
probe.expectMsg("bantonsson@somewhere.com");
|
|
|
|
|
probe.expectMsg("drewhk@somewhere.com");
|
|
|
|
|
probe.expectMsg("ktosopl@somewhere.com");
|
|
|
|
|
probe.expectMsg("mmartynas@somewhere.com");
|
|
|
|
|
probe.expectMsg("akkateam@somewhere.com");
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
@SuppressWarnings("unused")
|
|
|
|
|
public void callingExternalServiceWithMapAsyncAndSupervision() throws Exception {
|
2017-03-17 03:02:47 +08:00
|
|
|
new TestKit(system) {
|
2016-01-13 16:25:24 +01:00
|
|
|
final AddressSystem2 addressSystem = new AddressSystem2();
|
|
|
|
|
|
|
|
|
|
{
|
2019-01-12 04:00:53 +08:00
|
|
|
final Source<Author, NotUsed> authors =
|
|
|
|
|
tweets.filter(t -> t.hashtags().contains(AKKA)).map(t -> t.author);
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #email-addresses-mapAsync-supervision
|
2016-01-13 16:25:24 +01:00
|
|
|
final Attributes resumeAttrib =
|
2019-01-12 04:00:53 +08:00
|
|
|
ActorAttributes.withSupervisionStrategy(Supervision.getResumingDecider());
|
2016-01-20 10:00:37 +02:00
|
|
|
final Flow<Author, String, NotUsed> lookupEmail =
|
2016-01-13 16:25:24 +01:00
|
|
|
Flow.of(Author.class)
|
2019-01-12 04:00:53 +08:00
|
|
|
.mapAsync(4, author -> addressSystem.lookupEmail(author.handle))
|
|
|
|
|
.withAttributes(resumeAttrib);
|
2016-01-20 10:00:37 +02:00
|
|
|
final Source<String, NotUsed> emailAddresses = authors.via(lookupEmail);
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #email-addresses-mapAsync-supervision
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void callingExternalServiceWithMapAsyncUnordered() throws Exception {
|
2017-03-17 03:02:47 +08:00
|
|
|
new TestKit(system) {
|
2016-01-13 16:25:24 +01:00
|
|
|
final TestProbe probe = new TestProbe(system);
|
|
|
|
|
final AddressSystem addressSystem = new AddressSystem();
|
|
|
|
|
final EmailServer emailServer = new EmailServer(probe.ref());
|
|
|
|
|
|
|
|
|
|
{
|
2019-01-12 04:00:53 +08:00
|
|
|
// #external-service-mapAsyncUnordered
|
2016-01-20 10:00:37 +02:00
|
|
|
final Source<Author, NotUsed> authors =
|
2019-01-12 04:00:53 +08:00
|
|
|
tweets.filter(t -> t.hashtags().contains(AKKA)).map(t -> t.author);
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2016-01-20 10:00:37 +02:00
|
|
|
final Source<String, NotUsed> emailAddresses =
|
2019-01-12 04:00:53 +08:00
|
|
|
authors
|
|
|
|
|
.mapAsyncUnordered(4, author -> addressSystem.lookupEmail(author.handle))
|
|
|
|
|
.filter(o -> o.isPresent())
|
|
|
|
|
.map(o -> o.get());
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2016-01-20 10:00:37 +02:00
|
|
|
final RunnableGraph<NotUsed> sendEmails =
|
2019-01-12 04:00:53 +08:00
|
|
|
emailAddresses
|
|
|
|
|
.mapAsyncUnordered(
|
|
|
|
|
4, address -> emailServer.send(new Email(address, "Akka", "I like your tweet")))
|
|
|
|
|
.to(Sink.ignore());
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
sendEmails.run(mat);
|
2019-01-12 04:00:53 +08:00
|
|
|
// #external-service-mapAsyncUnordered
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void carefulManagedBlockingWithMapAsync() throws Exception {
|
2017-03-17 03:02:47 +08:00
|
|
|
new TestKit(system) {
|
2016-01-13 16:25:24 +01:00
|
|
|
final AddressSystem addressSystem = new AddressSystem();
|
|
|
|
|
final EmailServer emailServer = new EmailServer(getRef());
|
|
|
|
|
final SmsServer smsServer = new SmsServer(getRef());
|
|
|
|
|
|
|
|
|
|
{
|
2016-01-20 10:00:37 +02:00
|
|
|
final Source<Author, NotUsed> authors =
|
2019-01-12 04:00:53 +08:00
|
|
|
tweets.filter(t -> t.hashtags().contains(AKKA)).map(t -> t.author);
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
final Source<String, NotUsed> phoneNumbers =
|
|
|
|
|
authors
|
|
|
|
|
.mapAsync(4, author -> addressSystem.lookupPhoneNumber(author.handle))
|
|
|
|
|
.filter(o -> o.isPresent())
|
|
|
|
|
.map(o -> o.get());
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #blocking-mapAsync
|
2016-01-21 16:37:26 +01:00
|
|
|
final Executor blockingEc = system.dispatchers().lookup("blocking-dispatcher");
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2016-01-20 10:00:37 +02:00
|
|
|
final RunnableGraph<NotUsed> sendTextMessages =
|
2019-01-12 04:00:53 +08:00
|
|
|
phoneNumbers
|
|
|
|
|
.mapAsync(
|
|
|
|
|
4,
|
|
|
|
|
phoneNo ->
|
|
|
|
|
CompletableFuture.supplyAsync(
|
|
|
|
|
() -> smsServer.send(new TextMessage(phoneNo, "I like your tweet")),
|
|
|
|
|
blockingEc))
|
|
|
|
|
.to(Sink.ignore());
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
sendTextMessages.run(mat);
|
2019-01-12 04:00:53 +08:00
|
|
|
// #blocking-mapAsync
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2017-03-17 03:02:47 +08:00
|
|
|
final List<Object> got = receiveN(7);
|
|
|
|
|
final Set<Object> set = new HashSet<>(got);
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
assertTrue(set.contains(String.valueOf("rolandkuhn".hashCode())));
|
|
|
|
|
assertTrue(set.contains(String.valueOf("patriknw".hashCode())));
|
|
|
|
|
assertTrue(set.contains(String.valueOf("bantonsson".hashCode())));
|
|
|
|
|
assertTrue(set.contains(String.valueOf("drewhk".hashCode())));
|
|
|
|
|
assertTrue(set.contains(String.valueOf("ktosopl".hashCode())));
|
|
|
|
|
assertTrue(set.contains(String.valueOf("mmartynas".hashCode())));
|
|
|
|
|
assertTrue(set.contains(String.valueOf("akkateam".hashCode())));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void carefulManagedBlockingWithMap() throws Exception {
|
2017-03-17 03:02:47 +08:00
|
|
|
new TestKit(system) {
|
2016-01-13 16:25:24 +01:00
|
|
|
final TestProbe probe = new TestProbe(system);
|
|
|
|
|
final AddressSystem addressSystem = new AddressSystem();
|
|
|
|
|
final EmailServer emailServer = new EmailServer(probe.ref());
|
|
|
|
|
final SmsServer smsServer = new SmsServer(probe.ref());
|
|
|
|
|
|
|
|
|
|
{
|
2016-01-20 10:00:37 +02:00
|
|
|
final Source<Author, NotUsed> authors =
|
2019-01-12 04:00:53 +08:00
|
|
|
tweets.filter(t -> t.hashtags().contains(AKKA)).map(t -> t.author);
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
final Source<String, NotUsed> phoneNumbers =
|
|
|
|
|
authors
|
|
|
|
|
.mapAsync(4, author -> addressSystem.lookupPhoneNumber(author.handle))
|
|
|
|
|
.filter(o -> o.isPresent())
|
|
|
|
|
.map(o -> o.get());
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #blocking-map
|
2016-01-20 10:00:37 +02:00
|
|
|
final Flow<String, Boolean, NotUsed> send =
|
2019-01-12 04:00:53 +08:00
|
|
|
Flow.of(String.class)
|
|
|
|
|
.map(phoneNo -> smsServer.send(new TextMessage(phoneNo, "I like your tweet")))
|
|
|
|
|
.withAttributes(ActorAttributes.dispatcher("blocking-dispatcher"));
|
|
|
|
|
final RunnableGraph<?> sendTextMessages = phoneNumbers.via(send).to(Sink.ignore());
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
sendTextMessages.run(mat);
|
2019-01-12 04:00:53 +08:00
|
|
|
// #blocking-map
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
probe.expectMsg(String.valueOf("rolandkuhn".hashCode()));
|
|
|
|
|
probe.expectMsg(String.valueOf("patriknw".hashCode()));
|
|
|
|
|
probe.expectMsg(String.valueOf("bantonsson".hashCode()));
|
|
|
|
|
probe.expectMsg(String.valueOf("drewhk".hashCode()));
|
|
|
|
|
probe.expectMsg(String.valueOf("ktosopl".hashCode()));
|
|
|
|
|
probe.expectMsg(String.valueOf("mmartynas".hashCode()));
|
|
|
|
|
probe.expectMsg(String.valueOf("akkateam".hashCode()));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void callingActorServiceWithMapAsync() throws Exception {
|
2017-03-17 03:02:47 +08:00
|
|
|
new TestKit(system) {
|
2016-01-13 16:25:24 +01:00
|
|
|
final TestProbe probe = new TestProbe(system);
|
|
|
|
|
final EmailServer emailServer = new EmailServer(probe.ref());
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
final ActorRef database =
|
|
|
|
|
system.actorOf(Props.create(DatabaseService.class, probe.ref()), "db");
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
{
|
2019-01-12 04:00:53 +08:00
|
|
|
// #save-tweets
|
2016-01-20 10:00:37 +02:00
|
|
|
final Source<Tweet, NotUsed> akkaTweets = tweets.filter(t -> t.hashtags().contains(AKKA));
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2016-01-20 10:00:37 +02:00
|
|
|
final RunnableGraph<NotUsed> saveTweets =
|
2019-01-12 04:00:53 +08:00
|
|
|
akkaTweets
|
|
|
|
|
.mapAsync(4, tweet -> ask(database, new Save(tweet), Duration.ofMillis(300L)))
|
|
|
|
|
.to(Sink.ignore());
|
|
|
|
|
// #save-tweets
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
saveTweets.run(mat);
|
|
|
|
|
|
|
|
|
|
probe.expectMsg("rolandkuhn");
|
|
|
|
|
probe.expectMsg("patriknw");
|
|
|
|
|
probe.expectMsg("bantonsson");
|
|
|
|
|
probe.expectMsg("drewhk");
|
|
|
|
|
probe.expectMsg("ktosopl");
|
|
|
|
|
probe.expectMsg("mmartynas");
|
|
|
|
|
probe.expectMsg("akkateam");
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void illustrateOrderingAndParallelismOfMapAsync() throws Exception {
|
2017-03-17 03:02:47 +08:00
|
|
|
new TestKit(system) {
|
2016-01-13 16:25:24 +01:00
|
|
|
final TestProbe probe = new TestProbe(system);
|
|
|
|
|
final EmailServer emailServer = new EmailServer(probe.ref());
|
|
|
|
|
|
|
|
|
|
class MockSystem {
|
|
|
|
|
class Println {
|
|
|
|
|
public <T> void println(T s) {
|
2019-01-12 04:00:53 +08:00
|
|
|
if (s.toString().startsWith("after:")) probe.ref().tell(s, ActorRef.noSender());
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public final Println out = new Println();
|
|
|
|
|
}
|
2019-01-12 04:00:53 +08:00
|
|
|
|
2016-01-13 16:25:24 +01:00
|
|
|
private final MockSystem System = new MockSystem();
|
|
|
|
|
|
|
|
|
|
{
|
2019-01-12 04:00:53 +08:00
|
|
|
// #sometimes-slow-mapAsync
|
2016-01-21 16:37:26 +01:00
|
|
|
final Executor blockingEc = system.dispatchers().lookup("blocking-dispatcher");
|
2016-01-13 16:25:24 +01:00
|
|
|
final SometimesSlowService service = new SometimesSlowService(blockingEc);
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
final ActorMaterializer mat =
|
|
|
|
|
ActorMaterializer.create(
|
|
|
|
|
ActorMaterializerSettings.create(system).withInputBuffer(4, 4), system);
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
Source.from(Arrays.asList("a", "B", "C", "D", "e", "F", "g", "H", "i", "J"))
|
2019-01-12 04:00:53 +08:00
|
|
|
.map(
|
|
|
|
|
elem -> {
|
|
|
|
|
System.out.println("before: " + elem);
|
|
|
|
|
return elem;
|
|
|
|
|
})
|
|
|
|
|
.mapAsync(4, service::convert)
|
|
|
|
|
.runForeach(elem -> System.out.println("after: " + elem), mat);
|
|
|
|
|
// #sometimes-slow-mapAsync
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
probe.expectMsg("after: A");
|
|
|
|
|
probe.expectMsg("after: B");
|
|
|
|
|
probe.expectMsg("after: C");
|
|
|
|
|
probe.expectMsg("after: D");
|
|
|
|
|
probe.expectMsg("after: E");
|
|
|
|
|
probe.expectMsg("after: F");
|
|
|
|
|
probe.expectMsg("after: G");
|
|
|
|
|
probe.expectMsg("after: H");
|
|
|
|
|
probe.expectMsg("after: I");
|
|
|
|
|
probe.expectMsg("after: J");
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void illustrateOrderingAndParallelismOfMapAsyncUnordered() throws Exception {
|
2017-03-17 03:02:47 +08:00
|
|
|
new TestKit(system) {
|
2016-01-13 16:25:24 +01:00
|
|
|
final EmailServer emailServer = new EmailServer(getRef());
|
|
|
|
|
|
|
|
|
|
class MockSystem {
|
|
|
|
|
class Println {
|
|
|
|
|
public <T> void println(T s) {
|
2019-01-12 04:00:53 +08:00
|
|
|
if (s.toString().startsWith("after:")) getRef().tell(s, ActorRef.noSender());
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public final Println out = new Println();
|
|
|
|
|
}
|
2019-01-12 04:00:53 +08:00
|
|
|
|
2016-01-13 16:25:24 +01:00
|
|
|
private final MockSystem System = new MockSystem();
|
|
|
|
|
|
|
|
|
|
{
|
2019-01-12 04:00:53 +08:00
|
|
|
// #sometimes-slow-mapAsyncUnordered
|
2016-01-21 16:37:26 +01:00
|
|
|
final Executor blockingEc = system.dispatchers().lookup("blocking-dispatcher");
|
2016-01-13 16:25:24 +01:00
|
|
|
final SometimesSlowService service = new SometimesSlowService(blockingEc);
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
final ActorMaterializer mat =
|
|
|
|
|
ActorMaterializer.create(
|
|
|
|
|
ActorMaterializerSettings.create(system).withInputBuffer(4, 4), system);
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
Source.from(Arrays.asList("a", "B", "C", "D", "e", "F", "g", "H", "i", "J"))
|
2019-01-12 04:00:53 +08:00
|
|
|
.map(
|
|
|
|
|
elem -> {
|
|
|
|
|
System.out.println("before: " + elem);
|
|
|
|
|
return elem;
|
|
|
|
|
})
|
|
|
|
|
.mapAsyncUnordered(4, service::convert)
|
|
|
|
|
.runForeach(elem -> System.out.println("after: " + elem), mat);
|
|
|
|
|
// #sometimes-slow-mapAsyncUnordered
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2017-03-17 03:02:47 +08:00
|
|
|
final List<Object> got = receiveN(10);
|
|
|
|
|
final Set<Object> set = new HashSet<>(got);
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
assertTrue(set.contains("after: A"));
|
|
|
|
|
assertTrue(set.contains("after: B"));
|
|
|
|
|
assertTrue(set.contains("after: C"));
|
|
|
|
|
assertTrue(set.contains("after: D"));
|
|
|
|
|
assertTrue(set.contains("after: E"));
|
|
|
|
|
assertTrue(set.contains("after: F"));
|
|
|
|
|
assertTrue(set.contains("after: G"));
|
|
|
|
|
assertTrue(set.contains("after: H"));
|
|
|
|
|
assertTrue(set.contains("after: I"));
|
|
|
|
|
assertTrue(set.contains("after: J"));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-22 18:27:54 +09:00
|
|
|
@Test
|
|
|
|
|
public void illustrateSourceQueue() throws Exception {
|
|
|
|
|
new TestKit(system) {
|
|
|
|
|
{
|
2019-01-12 04:00:53 +08:00
|
|
|
// #source-queue
|
2019-01-17 12:16:52 +01:00
|
|
|
int bufferSize = 10;
|
|
|
|
|
int elementsToProcess = 5;
|
2018-05-22 18:27:54 +09:00
|
|
|
|
|
|
|
|
SourceQueueWithComplete<Integer> sourceQueue =
|
|
|
|
|
Source.<Integer>queue(bufferSize, OverflowStrategy.backpressure())
|
|
|
|
|
.throttle(elementsToProcess, Duration.ofSeconds(3))
|
|
|
|
|
.map(x -> x * x)
|
|
|
|
|
.to(Sink.foreach(x -> System.out.println("got: " + x)))
|
|
|
|
|
.run(mat);
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
Source<Integer, NotUsed> source = Source.from(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
|
2018-05-22 18:27:54 +09:00
|
|
|
|
|
|
|
|
source.map(x -> sourceQueue.offer(x)).runWith(Sink.ignore(), mat);
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
// #source-queue
|
2018-05-22 18:27:54 +09:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
2019-03-08 17:13:59 +01:00
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void illustrateSourceActorRef() throws Exception {
|
|
|
|
|
new TestKit(system) {
|
|
|
|
|
{
|
|
|
|
|
// #source-actorRef
|
|
|
|
|
int bufferSize = 10;
|
|
|
|
|
|
|
|
|
|
Source<Integer, ActorRef> source =
|
|
|
|
|
Source.actorRef(
|
|
|
|
|
bufferSize, OverflowStrategy.dropHead()); // note: backpressure is not supported
|
|
|
|
|
ActorRef actorRef =
|
|
|
|
|
source.map(x -> x * x).to(Sink.foreach(x -> System.out.println("got: " + x))).run(mat);
|
|
|
|
|
|
|
|
|
|
actorRef.tell(1, ActorRef.noSender());
|
|
|
|
|
actorRef.tell(2, ActorRef.noSender());
|
|
|
|
|
actorRef.tell(3, ActorRef.noSender());
|
2019-03-27 14:16:38 +01:00
|
|
|
actorRef.tell(
|
|
|
|
|
new akka.actor.Status.Success(CompletionStrategy.draining()), ActorRef.noSender());
|
2019-03-08 17:13:59 +01:00
|
|
|
// #source-actorRef
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|