Remove docs for ActorPub/Sub and write persistence query docs as stages (#26844)

* use separate db columns
* Use io dispatcher for sample stage
This commit is contained in:
Christopher Batey 2019-05-03 11:36:50 +01:00 committed by Patrik Nordwall
parent 2bbf13f707
commit c65bf2d276
22 changed files with 272 additions and 2194 deletions

View file

@ -1,161 +0,0 @@
/*
* Copyright (C) 2015-2019 Lightbend Inc. <https://www.lightbend.com>
*/
package jdocs.stream;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.stream.ActorMaterializer;
import akka.stream.Materializer;
import akka.stream.actor.AbstractActorPublisher;
import akka.stream.actor.ActorPublisherMessage;
import akka.stream.javadsl.Sink;
import akka.stream.javadsl.Source;
import jdocs.AbstractJavaTest;
import akka.testkit.javadsl.TestKit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class ActorPublisherDocTest extends AbstractJavaTest {
static ActorSystem system;
static Materializer mat;
@BeforeClass
public static void setup() {
system = ActorSystem.create("ActorPublisherDocTest");
mat = ActorMaterializer.create(system);
}
@AfterClass
public static void tearDown() {
TestKit.shutdownActorSystem(system);
system = null;
mat = null;
}
// #job-manager
public static class JobManagerProtocol {
public static final class Job {
public final String payload;
public Job(String payload) {
this.payload = payload;
}
}
public static class JobAcceptedMessage {
@Override
public String toString() {
return "JobAccepted";
}
}
public static final JobAcceptedMessage JobAccepted = new JobAcceptedMessage();
public static class JobDeniedMessage {
@Override
public String toString() {
return "JobDenied";
}
}
public static final JobDeniedMessage JobDenied = new JobDeniedMessage();
}
public static class JobManager extends AbstractActorPublisher<JobManagerProtocol.Job> {
public static Props props() {
return Props.create(JobManager.class);
}
private final int MAX_BUFFER_SIZE = 100;
private final List<JobManagerProtocol.Job> buf = new ArrayList<>();
@Override
public Receive createReceive() {
return receiveBuilder()
.match(
JobManagerProtocol.Job.class,
job -> buf.size() == MAX_BUFFER_SIZE,
job -> {
getSender().tell(JobManagerProtocol.JobDenied, getSelf());
})
.match(
JobManagerProtocol.Job.class,
job -> {
getSender().tell(JobManagerProtocol.JobAccepted, getSelf());
if (buf.isEmpty() && totalDemand() > 0) onNext(job);
else {
buf.add(job);
deliverBuf();
}
})
.match(ActorPublisherMessage.Request.class, request -> deliverBuf())
.match(ActorPublisherMessage.Cancel.class, cancel -> getContext().stop(getSelf()))
.build();
}
void deliverBuf() {
while (totalDemand() > 0) {
/*
* totalDemand is a Long and could be larger than
* what buf.splitAt can accept
*/
if (totalDemand() <= Integer.MAX_VALUE) {
final List<JobManagerProtocol.Job> took =
buf.subList(0, Math.min(buf.size(), (int) totalDemand()));
took.forEach(this::onNext);
buf.removeAll(took);
break;
} else {
final List<JobManagerProtocol.Job> took =
buf.subList(0, Math.min(buf.size(), Integer.MAX_VALUE));
took.forEach(this::onNext);
buf.removeAll(took);
}
}
}
}
// #job-manager
@Test
public void demonstrateActorPublisherUsage() {
new TestKit(system) {
private final SilenceSystemOut.System System = SilenceSystemOut.get(getTestActor());
{
// #actor-publisher-usage
final Source<JobManagerProtocol.Job, ActorRef> jobManagerSource =
Source.actorPublisher(JobManager.props());
final ActorRef ref =
jobManagerSource
.map(job -> job.payload.toUpperCase())
.map(
elem -> {
System.out.println(elem);
return elem;
})
.to(Sink.ignore())
.run(mat);
ref.tell(new JobManagerProtocol.Job("a"), ActorRef.noSender());
ref.tell(new JobManagerProtocol.Job("b"), ActorRef.noSender());
ref.tell(new JobManagerProtocol.Job("c"), ActorRef.noSender());
// #actor-publisher-usage
expectMsgEquals("A");
expectMsgEquals("B");
expectMsgEquals("C");
}
};
}
}

View file

@ -1,274 +0,0 @@
/*
* Copyright (C) 2015-2019 Lightbend Inc. <https://www.lightbend.com>
*/
package jdocs.stream;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.routing.ActorRefRoutee;
import akka.routing.RoundRobinRoutingLogic;
import akka.routing.Routee;
import akka.routing.Router;
import akka.stream.ActorMaterializer;
import akka.stream.Materializer;
import akka.stream.actor.AbstractActorSubscriber;
import akka.stream.actor.ActorSubscriberMessage;
import akka.stream.actor.MaxInFlightRequestStrategy;
import akka.stream.actor.RequestStrategy;
import akka.stream.javadsl.Sink;
import akka.stream.javadsl.Source;
import jdocs.AbstractJavaTest;
import akka.testkit.javadsl.TestKit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.*;
import java.time.Duration;
import static org.junit.Assert.assertEquals;
public class ActorSubscriberDocTest extends AbstractJavaTest {
static ActorSystem system;
static Materializer mat;
@BeforeClass
public static void setup() {
system = ActorSystem.create("ActorSubscriberDocTest");
mat = ActorMaterializer.create(system);
}
@AfterClass
public static void tearDown() {
TestKit.shutdownActorSystem(system);
system = null;
mat = null;
}
// #worker-pool
public static class WorkerPoolProtocol {
public static class Msg {
public final int id;
public final ActorRef replyTo;
public Msg(int id, ActorRef replyTo) {
this.id = id;
this.replyTo = replyTo;
}
@Override
public String toString() {
return String.format("Msg(%s, %s)", id, replyTo);
}
}
public static Msg msg(int id, ActorRef replyTo) {
return new Msg(id, replyTo);
}
public static class Work {
public final int id;
public Work(int id) {
this.id = id;
}
@Override
public String toString() {
return String.format("Work(%s)", id);
}
}
public static Work work(int id) {
return new Work(id);
}
public static class Reply {
public final int id;
public Reply(int id) {
this.id = id;
}
@Override
public String toString() {
return String.format("Reply(%s)", id);
}
}
public static Reply reply(int id) {
return new Reply(id);
}
public static class Done {
public final int id;
public Done(int id) {
this.id = id;
}
@Override
public String toString() {
return String.format("Done(%s)", id);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Done done = (Done) o;
if (id != done.id) {
return false;
}
return true;
}
@Override
public int hashCode() {
return id;
}
}
public static Done done(int id) {
return new Done(id);
}
}
public static class WorkerPool extends AbstractActorSubscriber {
public static Props props() {
return Props.create(WorkerPool.class);
}
final int MAX_QUEUE_SIZE = 10;
final Map<Integer, ActorRef> queue = new HashMap<>();
final Router router;
@Override
public RequestStrategy requestStrategy() {
return new MaxInFlightRequestStrategy(MAX_QUEUE_SIZE) {
@Override
public int inFlightInternally() {
return queue.size();
}
};
}
public WorkerPool() {
final List<Routee> routees = new ArrayList<>();
for (int i = 0; i < 3; i++)
routees.add(new ActorRefRoutee(getContext().actorOf(Props.create(Worker.class))));
router = new Router(new RoundRobinRoutingLogic(), routees);
}
@Override
public Receive createReceive() {
return receiveBuilder()
.match(
ActorSubscriberMessage.OnNext.class,
on -> on.element() instanceof WorkerPoolProtocol.Msg,
onNext -> {
WorkerPoolProtocol.Msg msg = (WorkerPoolProtocol.Msg) onNext.element();
queue.put(msg.id, msg.replyTo);
if (queue.size() > MAX_QUEUE_SIZE)
throw new RuntimeException("queued too many: " + queue.size());
router.route(WorkerPoolProtocol.work(msg.id), getSelf());
})
.match(
ActorSubscriberMessage.onCompleteInstance().getClass(),
complete -> {
if (queue.isEmpty()) {
getContext().stop(getSelf());
}
})
.match(
WorkerPoolProtocol.Reply.class,
reply -> {
int id = reply.id;
queue.get(id).tell(WorkerPoolProtocol.done(id), getSelf());
queue.remove(id);
if (canceled() && queue.isEmpty()) {
getContext().stop(getSelf());
}
})
.build();
}
}
static class Worker extends AbstractActor {
@Override
public Receive createReceive() {
return receiveBuilder()
.match(
WorkerPoolProtocol.Work.class,
work -> {
// ...
getSender().tell(WorkerPoolProtocol.reply(work.id), getSelf());
})
.build();
}
}
// #worker-pool
@Test
public void demonstrateActorPublisherUsage() {
new TestKit(system) {
{
final ActorRef replyTo = getTestActor();
// #actor-subscriber-usage
final int N = 117;
final List<Integer> data = new ArrayList<>(N);
for (int i = 0; i < N; i++) {
data.add(i);
}
final ActorRef worker =
Source.from(data)
.map(i -> WorkerPoolProtocol.msg(i, replyTo))
.runWith(Sink.<WorkerPoolProtocol.Msg>actorSubscriber(WorkerPool.props()), mat);
// #actor-subscriber-usage
watch(worker);
List<Object> got = new ArrayList<>(receiveN(N));
Collections.sort(
got,
new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof WorkerPoolProtocol.Done
&& o2 instanceof WorkerPoolProtocol.Done) {
return ((WorkerPoolProtocol.Done) o1).id - ((WorkerPoolProtocol.Done) o2).id;
} else return 0;
}
});
int i = 0;
for (; i < N; i++) {
assertEquals(
String.format("Expected %d, but got %s", i, got.get(i)),
WorkerPoolProtocol.done(i),
got.get(i));
}
assertEquals(String.format("Expected 117 messages but got %d", i), i, 117);
expectTerminated(Duration.ofSeconds(10), worker);
}
};
}
}