Java Akka:在ask中丢失了对'child.path.name'的引用

Java Akka:在ask中丢失了对'child.path.name'的引用,java,akka,completable-future,actor-model,Java,Akka,Completable Future,Actor Model,我正试图实现来自曼宁的《阿克卡行动手册》的Java版本。它是一个基于Actor模型的简单Http服务器,用于存储内存和检索一些事件。我保存事件没有问题。但在查询actor系统中的所有事件时,我确实遇到了一个问题 这是相关的,我放了三个点,而不是我认为与我的票房发行代码无关的代码——所有售票员的母公司负责管理每个活动的状态 public class BoxOffice extends AbstractActor { ... private Timeout timeout;

我正试图实现来自曼宁的《阿克卡行动手册》的Java版本。它是一个基于Actor模型的简单Http服务器,用于存储内存和检索一些事件。我保存事件没有问题。但在查询actor系统中的所有事件时,我确实遇到了一个问题

这是相关的,我放了三个点,而不是我认为与我的票房发行代码无关的代码——所有售票员的母公司负责管理每个活动的状态

public class BoxOffice extends AbstractActor {

    ...
    private Timeout timeout;
    final static String NAME = "boxOffice";

    //create child actors
    private ActorRef createTicketSeller(String name) {
        return getContext().actorOf(TicketSeller.props(name));
    }

    public BoxOffice(Timeout timeout) {
        this.timeout = timeout;
    }

    //the only method of an actor
    @Override
    public Receive createReceive() {
        return receiveBuilder()
                ...
                ...
                .match(GetEvent.class, this::receiveMsgGetEvent)
                .match(GetEvents.class, this::receiveMsgGetEvents)
                ...
                .build();
    }

    ...

    private void receiveMsgGetEvent(GetEvent getEvent) {
        Optional<ActorRef> maybeChild = getChildByName(getEvent.getName());
        log.info(String.format("Asking for event %s. Child is present: %s", getEvent.getName(), maybeChild.isPresent()));
        OptionalConsumer.of(maybeChild)
                .ifPresent(child -> child.forward(new TicketSeller.GetEvent(), getContext()))
                .ifNotPresent(() -> getSender().tell(Optional.empty(), getSelf()));
    }

    private void receiveMsgGetEvents(GetEvents getEvents) {
        //ask self() for each of the passed-in event
        List<CompletableFuture<Optional<Event>>> listFutureMaybeEvent =
                allChildrenStream()
                .map(child ->
                        ask(getSelf(), new GetEvent(child.path().name()), timeout)
                        .thenApply(obj -> (Optional<Event>) obj)
                        .toCompletableFuture())
                .collect(toList());

        CompletableFuture<Events> eventsFuture = toFutureEvents(listFutureMaybeEvent);
        pipe(eventsFuture, getContext().dispatcher()).to(sender());
    }

    private Stream<ActorRef> allChildrenStream() {
        return StreamSupport.stream(getContext().getChildren().spliterator(), false);
    }

    ...

    private CompletableFuture<Events> toFutureEvents(List<CompletableFuture<Optional<Event>>> futurePossibleEvents) {
        List<Event> events = futurePossibleEvents.stream()
                .map(CompletableFuture::join)
                .filter(Optional::isPresent)
                .map(Optional::get)
                .collect(toList());
        return CompletableFuture.supplyAsync(() -> new Events(events));
    }

    ...

    private Optional<ActorRef> getChildByName(String name) {
        return getContext().findChild(name);
    }

    static Props props(Timeout timeout) {
        return Props.create(BoxOffice.class, () -> new BoxOffice(timeout));
    }
另外值得注意的是,GetEvent在发送和被同一个actorlike接收之间花费了相当长的时间,但我觉得这不到20秒

这个问题可能是由于我的CompletableFutures操作造成的,但我已经尝试重现scala等效代码

上面的信息日志以及此消息:

INFO  [DeadLetterActorRef]: Message [java.util.Optional] from Actor[akka://mycompanyAkkaDemo/user/boxOffice#1554115585] to Actor[akka://mycompanyAkkaDemo/deadLetters] was not delivered. [1] dead letters encountered. This logging...
在配置超时20秒后打印的stacktrace之后打印:

ERROR [ActorSystemImpl]: Error during processing of request: 'Ask timed out on [Actor[akka://mycompanyAkkaDemo/user/boxOffice#1554115585]] after [20000 ms]. Sender[null] sent message of type "com.mycompany.demo.messages.boxoffice.GetEvents".'. Completing with 500 Internal Server Error response. To change default exception handling behavior, provide a custom ExceptionHandler.
akka.pattern.AskTimeoutException: Ask timed out on [Actor[akka://mycompanyAkkaDemo/user/boxOffice#1554115585]] after [20000 ms]. Sender[null] sent message of type "com.mycompany.demo.messages.boxoffice.GetEvents".
    at akka.pattern.PromiseActorRef$.$anonfun$defaultOnTimeout$1(AskSupport.scala:595)
    at akka.pattern.PromiseActorRef$.$anonfun$apply$1(AskSupport.scala:605)
    at akka.actor.Scheduler$$anon$4.run(Scheduler.scala:140)
    ...
    at java.lang.Thread.run(Thread.java:748)
ERROR [OneForOneStrategy]: akka.pattern.AskTimeoutException: Ask timed out on [Actor[akka://mycompanyAkkaDemo/user/boxOffice#1554115585]] after [20000 ms]. Sender[null] sent message of type "com.mycompany.demo.messages.boxoffice.GetEvent".
java.util.concurrent.CompletionException: akka.pattern.AskTimeoutException: Ask timed out on [Actor[akka://mycompanyAkkaDemo/user/boxOffice#1554115585]] after [20000 ms]. Sender[null] sent message of type "com.mycompany.demo.messages.boxoffice.GetEvent".
    at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:292)
    at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:308)
    at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:593)
    ...
Caused by: akka.pattern.AskTimeoutException: Ask timed out on [Actor[akka://mycompanyAkkaDemo/user/boxOffice#1554115585]] after [20000 ms]. Sender[null] sent message of type "com.mycompany.demo.messages.boxoffice.GetEvent".
    at akka.pattern.PromiseActorRef$.$anonfun$defaultOnTimeout$1(AskSupport.scala:595)
    ... 11 common frames omitted

这里的问题是调度员被阻塞了

在JVM上,由操作系统线程支持的线程在内存和进程调度程序开销方面都很昂贵。Akka的优点之一是,它允许您在更少的线程上运行多个参与者,从而更有效地使用线程

这很好,但确实意味着您不应该在演员内部执行阻塞调用。此处的CompletableFuture::join调用被阻塞,这可能是问题的原因


通过避免阻塞调用和使用异步API,如CompletableFuture.allOf,您的问题应该会消失。

CompletableFuture::join block不是吗?我想是的,这将是一个以异步方式重写的东西。谢谢你的提示@arnoteneglen!最后,我还是加入了线程,但是使用CompletableFuture.allOf,正如这里所建议的:你想把你的评论移到答案部分吗?听起来好像它没有阻塞就加入了,所以听起来很棒!我将尝试更概括一点以获得答案;。
ERROR [ActorSystemImpl]: Error during processing of request: 'Ask timed out on [Actor[akka://mycompanyAkkaDemo/user/boxOffice#1554115585]] after [20000 ms]. Sender[null] sent message of type "com.mycompany.demo.messages.boxoffice.GetEvents".'. Completing with 500 Internal Server Error response. To change default exception handling behavior, provide a custom ExceptionHandler.
akka.pattern.AskTimeoutException: Ask timed out on [Actor[akka://mycompanyAkkaDemo/user/boxOffice#1554115585]] after [20000 ms]. Sender[null] sent message of type "com.mycompany.demo.messages.boxoffice.GetEvents".
    at akka.pattern.PromiseActorRef$.$anonfun$defaultOnTimeout$1(AskSupport.scala:595)
    at akka.pattern.PromiseActorRef$.$anonfun$apply$1(AskSupport.scala:605)
    at akka.actor.Scheduler$$anon$4.run(Scheduler.scala:140)
    ...
    at java.lang.Thread.run(Thread.java:748)
ERROR [OneForOneStrategy]: akka.pattern.AskTimeoutException: Ask timed out on [Actor[akka://mycompanyAkkaDemo/user/boxOffice#1554115585]] after [20000 ms]. Sender[null] sent message of type "com.mycompany.demo.messages.boxoffice.GetEvent".
java.util.concurrent.CompletionException: akka.pattern.AskTimeoutException: Ask timed out on [Actor[akka://mycompanyAkkaDemo/user/boxOffice#1554115585]] after [20000 ms]. Sender[null] sent message of type "com.mycompany.demo.messages.boxoffice.GetEvent".
    at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:292)
    at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:308)
    at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:593)
    ...
Caused by: akka.pattern.AskTimeoutException: Ask timed out on [Actor[akka://mycompanyAkkaDemo/user/boxOffice#1554115585]] after [20000 ms]. Sender[null] sent message of type "com.mycompany.demo.messages.boxoffice.GetEvent".
    at akka.pattern.PromiseActorRef$.$anonfun$defaultOnTimeout$1(AskSupport.scala:595)
    ... 11 common frames omitted