John Papastergiou
John Papastergiou

Reputation: 1019

How to force an actor to fail after a timeout in akka

I'm using a master-slave architecture in akka using java. The master receives messages that represent job commands which he routes to the slaves. Those jobs involve calling a third party library that is not open source and sometimes crashes just by hanging and blocking the execution without throwing any exception. Akka does not recognize this as a failure and keeps sending messages to the Mailbox this actor is using but since the first call blocks indefinitely, the rest of the commands in the mailbox will never get executed.

My goal is to emulate this type of failure with a timeout expiration and an exception so as to forward the whole incident to the Failure Strategy build in akka. So my question is, can I somehow configure an actor to throw an exception after a message is received and it's execution is not completed after the timeout ?

If not, what are some other alternatives to handle such a case without performing any blocking operations ? I was thinking to encapsulate the execution in a Future and call it from inside an actor that will block on that future for a timeout. It works but as suggested by many, blocking, is not a good solution in akka.

Upvotes: 1

Views: 1088

Answers (1)

Roland Kuhn
Roland Kuhn

Reputation: 15472

There is no need to block two threads where one suffices: just have one actor which coordinates how many calls to that (horribly unreliable) API are permitted and launch them in Futures (as cmbaxter recommends you should NOT use the same ExecutionContext as the actor is running on, I’d use a dedicated one). Those Futures should then be combined using firstCompletedOf with a timeout Future:

import akka.pattern.after
import context.system.scheduler
import scala.concurrent.duration._

implicit val ec = myDedicatedDangerousActivityThreadPool
val myDangerousFuture = ???
val timeout = after(1.second, scheduler(throw new TimeoutException)
val combined = Future.firstCompletedOf(myDangerousFuture, timeout)

Then you pipe that back to your actor in some suitable fashion, e.g. mapping its result value into a message type or whatever you need, and keep track of how many are outstanding. I would recommend wrapping the myDangerousFuture in a Circuit Breaker for improved responsiveness in the failure case.

Upvotes: 3

Related Questions