Which actor methods are ok to call in a future callback?

575 views
Skip to first unread message

John Ulric

unread,
Sep 21, 2015, 11:37:57 AM9/21/15
to Akka User List
Hi all, I create a Future in an actor's onReceive method, and use onComplete to trigger a side-effect when that future completes, like this:

public void onReceive(Object message) throws Exception {
final ActorRef sender = sender();
    Future f = ...;
f.onComplete(new OnComplete() {
@Override
public void onComplete(Throwable throwable, Object object) throws Throwable {
// Can use final sender here.
// What actor methods are allowed here?
}
    }, context().dispatcher());
}

It's clear that one must not modify the actor's state from within the onComplete callback, and it's clear that one must use the self() and sender() methods outside the callback and pass it into the onComplete as finals. But what other actor methods are allowed inside the onComplete method? Is it ok to use context(), eg?

Thanks.

Heiko Seeberger

unread,
Sep 21, 2015, 12:01:50 PM9/21/15
to akka...@googlegroups.com
Don’t ever use callbacks in actors, you’ll shoot yourself in the foot sooner or later. Use `pipeTo` to send the result of the `Future` to `self` and handle it (and `Statue.Failure`) like any other message.

Heiko

--

Heiko Seeberger
Twitter: @hseeberger

--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.

Roland Kuhn

unread,
Sep 21, 2015, 12:47:27 PM9/21/15
to akka-user
The simple and direct answer is that none of the methods are allowed to be called from an asynchronous context.

Regards,

Roland

--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.



Dr. Roland Kuhn
Akka Tech Lead
Typesafe – Reactive apps on the JVM.
twitter: @rolandkuhn


John Ulric

unread,
Sep 22, 2015, 9:20:55 AM9/22/15
to Akka User List
@Heiko, @Roland, thanks. The callback in my case essentially makes a decision where to send the future result (to self, to a delegee actor, to the calling actor) plus some error handling, logging and monitoring, so it is a pipe, essentially. I found the code more readable when I make these decisions here in the callback, instead of piping the result to self, making the decisions, and forwarding the message again. Do you think this is an acceptable pattern or would you absolutely discourage to the use of a callback here?

Heiko Seeberger

unread,
Sep 22, 2015, 2:51:14 PM9/22/15
to akka...@googlegroups.com
Let me say it again: Don’t ever use callbacks in actors! How could I say it any clearer?

Heiko

--

Heiko Seeberger
Twitter: @hseeberger

On 22 Sep 2015, at 14:20, John Ulric <uja...@gmail.com> wrote:

@Heiko, @Roland, thanks. The callback in my case essentially makes a decision where to send the future result (to self, to a delegee actor, to the calling actor) plus some error handling, logging and monitoring, so it is a pipe, essentially. I found the code more readable when I make these decisions here in the callback, instead of piping the result to self, making the decisions, and forwarding the message again. Do you think this is an acceptable pattern or would you absolutely discourage to the use of a callback here?

Justin du coeur

unread,
Sep 22, 2015, 3:05:32 PM9/22/15
to akka...@googlegroups.com
On Tue, Sep 22, 2015 at 9:20 AM, John Ulric <uja...@gmail.com> wrote:
@Heiko, @Roland, thanks. The callback in my case essentially makes a decision where to send the future result (to self, to a delegee actor, to the calling actor) plus some error handling, logging and monitoring, so it is a pipe, essentially. I found the code more readable when I make these decisions here in the callback, instead of piping the result to self, making the decisions, and forwarding the message again. Do you think this is an acceptable pattern or would you absolutely discourage to the use of a callback here?

If you want to use this pattern, I recommend you look into the Requester library, which is designed to provide ask-like callbacks while actually *operating* like pipeTo.  This sort of thing is why I wrote Requester.

Suffice it to say, Requester adds the request() function, which is similar to ask() but returns a RequestM instead of a Future.  It has many of the same functions as Future -- onComplete, map, flatMap, etc -- but they actually run in the Actor's main receive loop instead of in some arbitrary thread.

However, I will caveat that it's never been sanity-checked with Java -- I only use Scala, and haven't really given much thought to the API from a Java perspective.  If you find problems using it from there, please bring them to my attention.

Richard Bradley

unread,
Sep 28, 2015, 9:47:42 AM9/28/15
to Akka User List
On this subject, I've wondered for a while why Actors don't expose an ExecutionContext which executes all Future callbacks on their event loop, thus eliminating this problematic restriction on Future callbacks entirely? 
http://stackoverflow.com/questions/26912919/how-to-run-futures-on-the-current-actors-dispatcher-in-akka

I suppose it would be a backwards compatibility break and might possibly introduce some unexpected bottlenecks, but it seems to me like it would be a better tradeoff than trying to outlaw Future operations in an Actor context, which is a common pitfall for Akka users.

Your Requester library, Justin, looks to do just that for the specific case of Asks. It looks pretty useful; I might start using it.

Viktor Klang

unread,
Sep 28, 2015, 9:50:28 AM9/28/15
to Akka User List
Richard,

what would happen if the actor is dead when the Future is to be executed?

--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.



--
Cheers,

Roland Kuhn

unread,
Sep 28, 2015, 10:18:20 AM9/28/15
to akka-user
My main consideration here is that such a dispatcher would make it very convenient to have multiple concurrent entry points into the Actor’s behavior, where with the current recommendation there is only one—the active behavior. While classical data races are excluded by the synchronization afforded by the proposed ExecutionContext, it would still allow higher-level races by suspending a logical thread and not controlling the intermediate execution of other messages. In a nutshell, I don’t think this would make the Actor easier to reason about, quite the opposite.

Regards,

Roland

--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.

Richard Bradley

unread,
Sep 28, 2015, 10:49:27 AM9/28/15
to Akka User List
Good point. I think you are spot on here -- this would be a minefield in practice, even more so than occasionally forgetting not to use Futures inside Actors.
I hadn't thought about switchable Actor behaviors.

(I tend to agree with this blog post and we use a lot more Futures than Actors in our Akka HTTP (and Spray) apps: http://noelwelsh.com/programming/2013/03/04/why-i-dont-like-akka-actors/ . Perhaps the upcoming typed Actors will make things better in that regard.)

(I'll post your comment as an answer to my SO question.)

Thanks,


Rich

Odd Möller

unread,
Sep 28, 2015, 11:42:36 AM9/28/15
to Akka User List
For what it's worth, we use a homemade solution for this problem. It looks quite a lot like one described in an answer to your stackoverflow question (but with a bit of sugar on top). Basically we allow a future to be marked as "local" which will cause all its callbacks to be executed via the normal message handling of the defining actor, but without having to move the callback handling code out of the future callback and into a message handler. This has worked out quite well in practice, but Rolands observations still stand of course. You can find the code at: https://gist.github.com/odd/e356e178bfa178f727e3 

Greetings
Odd

Justin du coeur

unread,
Sep 28, 2015, 1:06:54 PM9/28/15
to akka...@googlegroups.com
On Mon, Sep 28, 2015 at 10:49 AM, Richard Bradley <richard.brad...@gmail.com> wrote:
Good point. I think you are spot on here -- this would be a minefield in practice, even more so than occasionally forgetting not to use Futures inside Actors.
I hadn't thought about switchable Actor behaviors.

Yaas.  Requester works very well in "steady state" Actors, but often requires a little care even in simple behavior-switching ones.  (Eg, the Actor starts in state A while it is booting, then moves to state B and stays there once it is ready.)  I haven't even tried using it with FSM; I suspect it would be fraught.

OTOH, I'll play Devil's Advocate for a minute: *any* inter-Actor communication is pretty fraught when you're dealing with a highly mode-switchable Actor, and reasoning about the interactions is never going to be easy.  I'm not sure the Requester approach makes it any worse than it already is.  I've wound up strictly avoiding such situations, because they seem to be a recipe for bugs.

And the truth is, I've been thinking about Richard's question for some months now -- the more I play with Requester, the more I think that a built-in Actor-specific ExecutionContext would be bloody useful.  Yes, it would have limitations; yes, it would drop results on the floor if the Actor dies.  In all my usage, though (and Querki uses Requester *enormously* often), that's been the right answer.

By now, I'm fairly comfortable putting a stake in the ground that Futures should only be used in an Actor when they are *owned* by that Actor.  They should *always* execute within the Actor's receive loop; it should be impossible to run them *outside* that loop; and they *should* simply have their results dropped on the floor if the receiving Actor has died.  I have yet to come up with an exception to those rules, in three years of heavy coding in this model.  It's why I eventually decided that the request() function should shadow `?` -- Actors should never, ever use ask() unless it is wrapped by request(), and I've wound up wrapping all of my other Futures with loopback().  (Requester's function that essentially transforms a Future to a RequestM.)

I don't understand the ExecutionContext code nearly well enough to do this myself yet, or I'd have tried it by now.  (I've dug into the code with an eye towards trying a couple of times.)  But I do actually believe that everything would work quite a lot better if this were the standard model, at which point Requester becomes quietly redundant.  Given how many problems are caused by Futures within Actors, I think folks aren't considering this alternative seriously enough.  At the very least, an easy "opt-in" way to get an implicit ExecutionContext within this Actor would, I believe, be a huge win...

Justin du coeur

unread,
Sep 28, 2015, 1:07:51 PM9/28/15
to akka...@googlegroups.com
(And now that I see Odd's code, I'm going to have to play with this...)

John Ulric

unread,
Sep 29, 2015, 2:07:37 PM9/29/15
to Akka User List
@Heiko: I heard you loud an clear. Thank you. 

I'm still confused, however. So within the onReceive method of an actor, I understand it's allowed to call pipe like this, correct?

Patterns.pipe(Patterns.ask(otherActor, message, timeout), context().dispatcher());

If yes, what's the way if I want to wrap the ask result to add some information for subsequent processing that the otherActor cannot do? Would it be OK to call something like this?

Patterns.pipe(Patterns.ask(otherActor, message, timeout).map(new Mapper<Object, Object>() {
@Override
public Object apply(Object parameter) {
return new WrappedMessage(message, otherImmutableParameter);
}
}, context().dispatcher()), context().dispatcher());

Or does using the future's map method again violate the "don't use future callbacks in actors" rule?

Sorry if this sounds stupid, but wrapping one's head around the Scala–Java gap ain't easy, at least for me.

rta...@twitter.com

unread,
Sep 29, 2015, 3:09:35 PM9/29/15
to Akka User List
I don't think there's much reason to use pipe and ask together.  You could just do this:

otherActor.tell(message, targetActor);

Doesn't allow you to wrap whatever message otherActor will reply with though.

John Ulric

unread,
Sep 29, 2015, 4:26:11 PM9/29/15
to Akka User List
@Ryan, thanks. But as I see it, wrapping is essential here. 

Please allow me to explain what I'm trying to do. Maybe I'm completely mistaken and there's a much better way to do it:

There are three parties (code components), I'll name them caller, parent and child. The caller (actor or non-actor, doesn't matter) essentially wants to send a message to the child actor and has a fixed contract with that child actor. Part of that contract is that the child actor responds to each message with either a Status.Success or Status.Failure. For each message, the child actor performs an action that is prone to failure. So there is an intermediate parent actor that relays messages between the caller and the child actor. The job of the parent actor is to do some bookkeeping of which messages failed and how often an when and to organize a controlled retry procedure like backoff, circuit breaker, whatever plus monitoring. 

That parent actor is intended to be generic, knowing nothing of the message contents between the caller and the child. So if I used just "tell" without a way to wrap the failed message with the retry status, there's no way I see for the parent actor to keep track of the retry status of each of the relayed messages. Except either modifying the child contract to recognize a wrapped message (not possible here) or keep persistent state in the parent actor for each relayed message (seems very unpretty to me).

Roland Kuhn

unread,
Sep 30, 2015, 1:44:39 AM9/30/15
to akka-user
Hi John,

keeping the per-message state in a Future transformation is the right thing to do in this case, your mapping code example is correct. Another alternative would be to have the “parent” create another child Actor per request that is responsible for the retries.

Regards,

Roland

--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages