scala - How to propagate error in future to parent actor -


i try understand failure handling akka , futures. example have parent , child actors.

child actor have 2 failure cases:
case 1) error happens while message processing
case 2) error happens inside future

i need propagate error parent in both cases, in second case it's not happens. what's doing wrong?

import akka.actor.supervisorstrategy.{decider, stop} import akka.actor.{actor, actorref, actorsystem, oneforonestrategy, props, supervisorstrategy} import akka.testkit.{testkit, testprobe} import org.junit.{after, before, test}  import scala.concurrent.future import scala.util.{failure, success}   class parent(_case: string, probe: actorref) extends actor {    val child = context.actorof(props(new child(_case)), "mylittlechild")    final val defaultstrategy: supervisorstrategy = {     def defaultdecider: decider = {       case ex: exception =>         probe ! ex         stop     }      oneforonestrategy()(defaultdecider)   }    override def supervisorstrategy: supervisorstrategy = defaultstrategy    override def receive: receive = {     case msg => unhandled(msg)   }  }  class child(_case: string) extends actor {    implicit val ec = context.dispatcher    override def prestart(): unit = {     self ! _case   }     override def receive: receive = {     case "case1" => throw new runtimeexception("fail")     case "case2" => future[string] {       throw new runtimeexception("fail")     }.oncomplete {       case success(s) => println(s)       case failure(e) =>         throw e     }     case msg => unhandled(msg)   } }   class testexample {    protected implicit var system: actorsystem = _    @before   def setup(): unit = {     system = actorsystem.create("test")   }    @after   def teardown(): unit = {     testkit.shutdownactorsystem(system)   }    @test   def case1(): unit = {     val testprobe = testprobe()     system.actorof(props(new parent("case1", testprobe.ref)))     testprobe expectmsgclass classof[runtimeexception]   }    @test   def case2(): unit = {     val testprobe = testprobe()     system.actorof(props(new parent("case2", testprobe.ref)))     testprobe expectmsgclass classof[runtimeexception]   }  } 

to test pass, send exception actor , rethrow exception outside oncomplete callback:

override def receive: receive = {   case "case1" => throw new runtimeexception("fail")   case "case2" =>     future[string] {       throw new runtimeexception("fail")     }.oncomplete {       case success(s) => println(s)       case failure(e) =>         self ! e     }   case e: runtimeexception => throw e   case msg => unhandled(msg) } 

however, if must use future in actor (e.g., third-party library methods return future), there better ways handle exceptions. example, database api mentioned in comment (databaseapi.load(): future[rows]), parent actor send loaddb message child, , child send rows or error message parent. child's behavior following:

def receive = {   case loaddb =>     val s = sender // capture sender     databaseapi       .load       .oncomplete {         case success(rows) =>           s ! rows         case failure(e) =>           s ! dbfailure(e)       }   case ... } 

an important note make local copy of sender reference when child receives loaddb message in order have reference correct sender inside oncomplete callback. if called sender inside callback, give erroneous results because sender have changed time callback executed, explained here. (unlike sender, self immutable, it's safe use self inside oncomplete.)


Comments

Popular posts from this blog

networking - Vagrant-provisioned VirtualBox VM is not reachable from Ubuntu host -

c# - ASP.NET Core - There is already an object named 'AspNetRoles' in the database -

ruby on rails - ArgumentError: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true -