22

Is there a standard pattern to deal with exceptions within actors in Akka.NET?

I saw some patterns to create supervisors, but it seems the SupervisorStrategy is a way to deal with things that cannot be resolved by the actor.

I have an actor that receives lots of data and needs to store it in an external server. The external database may be unreachable. If it is, the server may be restarting or the network may be down. I don't need to restart the actor or anything, I just want to notify the sender with some information about what is happening, so he can persist the message on disk and reschedule for later.

The sender is not a parent of this actor connecting to the database. Should I create a supervisor just to handle this as well? Or should I encapsulate my receive handlers in try/catch blocks and just use Tell to notify the senders a with a custom response as if it was a normal message?

I know there is a Failure class, but I'm not sure if I'm suppose to use that for this situation.

user247702
  • 23,641
  • 15
  • 110
  • 157
Natan
  • 4,686
  • 5
  • 30
  • 48
  • 2
    Roger's answer is correct, but I wanted to link to a detailed explanation of how hierarchical supervision and the error kernel pattern both work in Akka.NET: http://petabridge.com/blog/how-actors-recover-from-failure-hierarchy-and-supervision/ – Aaronontheweb Feb 09 '15 at 18:20

1 Answers1

19

Yes there is. First of all, always delegate dangerous work to child actors, give them all your knifes, flame thrower and such. if they crash and burn, your state is still intact and you can spawn new children.

So for the unreachable database example; Spin up a DB-communication actor. You can then let this actor have two states, DB up and DB down, this can be modeled as an FSM or using Become/Unbecome.

So when a message arrives and requesting a DB query, if things blow up, the DB communicator actor puts it self into DB-Down state. If any query is received in DB-Down state, you can immediately respond with a Failure event.

So how do we go from DB-Down to to DB-Up again? The DB-Communicator actor can ping it self using ScheduleOnce, e.g. pass it self a "CheckDBStatus" message every x seconds. When the CheckDBStatus message is received, you check if DB is up again, and if so, you revert back to DB-Up state.

This way, you will not flood your DB in scenarios where it is unable to respond due to high load, adding more load in that case will only make things worse. So this kind of circuit breaker will prevent that from happening.

So in short:

In DB-Up state:

If a DBQuery message is received, try to run the query, and send back the response. if things blow up, go directly to DB-Down state and respond with a failure event.

In DB-Down state: if a DBQuery message is received, respond with a Failure event directly w/o touching the DB. Ping yourself every x seconds to see if DB is up, and revert to DB-Up state if possible.

In this scenario, you would not use any supervisor to transit the state, normal try/catch would be enough to deal with this.

Hope this clear things up.

Roger Johansson
  • 22,764
  • 18
  • 97
  • 193
  • Yes, it does. Just one thing: is a `Failure` event just a custom message I create and send with `Tell`, or is there something special to it? – Natan Feb 08 '15 at 18:29
  • Its just a common event, there is a built in "Failure" event for general purposes also – Roger Johansson Feb 08 '15 at 19:15
  • Am I right this DB-communication actor should be a top-level actor? – Monsignor May 21 '16 at 18:21
  • When you say "respond with a `Failure`" event, could you be more specific? Do you mean `Akka.Actor.Failure` or `Akka.Actor.Status.Failure` or something else? When I respond to an `Ask()` with either of those classes, I seem to get an invalid cast exception trying to cast the Failure to the intended return type instead of re-throwing the exception, so the original error is lost in favor of the invalid cast error. – Joel Mueller Nov 28 '16 at 18:19
  • This is common pattern in distribute systems and it's called Circuit Breaker. AFAIK there's implementation of this actor in Akka(.NET) as well – dragan.stepanovic Dec 09 '16 at 12:38
  • 1
    @JoelMueller not an answer to your question, but some info I managed to dig up: `Akka.Actor.Failure` was [added as part of the supervisor implementation](https://github.com/akkadotnet/akka.net/commit/2af4917), its usage there was [removed as part of the actor cell fault handling implementation](https://github.com/akkadotnet/akka.net/commit/d66a61e) but the class remained. `Akka.Actor.Status.Failure` is part of [remoting](https://github.com/akkadotnet/akka.net/commit/e74d285): *"[...] Used for internal ACKing protocol, but also exposed as a utility class for user-specific ACKing if needed."* – user247702 Jul 19 '17 at 12:36
  • 1
    @JoelMueller Did you ever find a answer to this? I am experiencing the same Failure casting exception and losing my actual exception. – EmberZ Aug 09 '18 at 10:25
  • @Monsignor No, the exact opposite. The DB-communication actor should be a child at the very bottom of the hierarchy and should be considered disposable. If the DB-communication actor throws an unhandled exception, let it die and replace it with a new instance of DB-communicaton. This is called the 'character actor' pattern and is explained in detail here: https://petabridge.com/blog/top-akkadotnet-design-patterns/ – James Allan Oct 17 '18 at 08:11