Ivan Poliakov
Ivan Poliakov

Reputation: 2475

How to combine Akka's supervision strategy with more specific irrecoverable error handling?

Say I have the following simple model: a single top-level actor (e.g. ReportService) that accepts requests for slow asynchronous operations and uses a number of delegate actors to carry out the failure-prone sub-tasks, following the Error Kernel pattern.

The sub-tasks are to retrieve data from the database, to produce a report file, to publish the file on a file storage somewhere etc.

When one of the top-level request tasks completes, I want the ReportService actor to notify the requesting user of its completion.

So far this all fits very well into my understanding of the actor model, however I don't understand how to handle irrecoverable failure cases gracefully. The supervision strategy etc. is all quite clear but in case if the request cannot be completed after several retries, how do I send the user a notification detailing the specific error that happened?

For example, if I run out of disk space there isn't much I can do to recover. I want the ReportService to be able to identify that the operation failed at this particular stage and send the notification explaining that to the user. My current solution is to wrap the errors manually inside the child actors and basically send an Either type message, but this does not seem to fit very well into the "let it crash" philosophy.

TL;DR: is there a way to access the throwable that caused the child actor to fail in the parent actor with the intent to forward it somewhere else?

Upvotes: 0

Views: 146

Answers (1)

thwiegan
thwiegan

Reputation: 2173

You can access the throwable within your supervisory strategy implementation inside the parent actor (from Akka Docs):

val supervisorStrategy =
  OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
    case _: ArithmeticException      => Resume
    case _: NullPointerException     => Restart
    case _: IllegalArgumentException => Stop
    case _: Exception                => Escalate
  }

EDIT

In your case you could do something like this:

val supervisorStrategy =
      AllForOneStrategy {
        case e: Throwable => 
            notifyUser(e)
            Stop
      }

EDIT 2 in response to comment

According to Docs (Note) you can obtain a reference to the sending actor.


Remark:

Another option would be to write a custom exception with all the needed information and just throw that instead of the default exceptions.

Upvotes: 1

Related Questions