Search code examples
javaakka

Is it possible to use Akka Patterns.ask() where a classic actor asks a typed actor?


Using Akka (Java) I am attempting to use the ask pattern (akka.pattern.Patterns.ask) where the asker is a classic actor and the askee is a typed actor. I am attempting something like this in the classic actor

Patterns.ask(Adapter.toClassic(typedActor), new TypedActor.Message(Adapter.toTyped(self())), timeout));

In the typed actor, the message is seen and replied to (e.g., like I show below), but the ask times out

msg.replyTo.tell(new Response());

Is this possible, and if so, could you help me with a simple example for how to do this in Java?


Solution

  • It looks like you're using Akka Classic's implementation of the ask pattern, akka.pattern.Patterns.ask. This implementation is logically equivalent (there are some slight optimizations under the hood) to spawning an actor which schedules a timeout message to itself and then sending a message to the askee purporting to be from the spawned actor. The spawned actor completes the future successfully if it gets a response before the timeout message or fails it with a timeout otherwise.

    In

    Patterns.ask(Adapter.toClassic(typedActor), new TypedActor.Message(Adapter.toTyped(self())), timeout));
    

    you're setting the classic actor which initiated the ask as the replyTo on the message, so the response from the typed actor goes to that classic actor, not to the actor which ask spawned, so that spawned actor will report that the ask timed out. The typed behavior doesn't see the "return address" on the classic envelope.

    The easiest fix is probably to use the Akka Typed ask pattern, akka.actor.typed.javadsl.AskPattern.ask, which would look something like:

    AskPattern.ask(
        typedActor,
        replyTo -> new TypedActor.Message(replyTo),
        timeout,
        Adapter.toTyped(getContext().getSystem()).scheduler()
    )
    

    The replyTo -> new TypedActor.Message(replyTo) injects the "reply-to" address into the request.

    Note that while Patterns.ask returns a Scala future, this returns a Java CompletionStage: you'll most likely want to pipe the returned CompletionStage to the classic actor with

    Patterns.pipe(csFromAsk, getContext().dispatcher()).to(self())
    

    Note that blocking a thread while waiting for the Future from Patterns.ask or CompletionStage from AskPattern.ask is not a good idea and can create deadlock.