Akka and its Error Kernel

给你一囗甜甜゛ 提交于 2019-12-05 18:08:44

I am able to answer only the first question (and in future, please place only one question in a post). Consider, for example, a database connection, which is inherently blocking. In order to allow actors to connect to a database, programmer should create a dedicated thread (or a thread pool) with a queue of database requests. A request contains a database statement and a reference to the actor which is to receive the result. The dedicated thread reads requests in a loop, accesses the database, sends the result to the referenced actor etc. The request queue is blocking - when there are no requests, the connection thread is blocked in the queue.take() operation.

So the access to a database is split in two actors - one places a request to the queue, and the other handles the result.

UPDATE: Java code sketch (I am not strong in Scala).

class Request {
  String query;
  ActorRef handler;
}

class DatabaseConnector implements Runnable {
  LinkedBlockingQueue<Request> queue=new LinkedBlockingQueue<Request>();
  Thread  t = new Thread(this);
  {t.start();}

  public void sendRequest(Request r) {
     queue.put(r);
  }

  public void run() {
    for (;;) {
      Request r=queue.take();
      ResultSet res=doBlockingCallToJdbc(r.query);
      r.handler.sendOneWay(res);
    }
}

Here is the answer for your second question. Right from the Akka Doc:

If one actor carries very important data (i.e. its state shall not be lost if avoidable), this actor should source out any possibly dangerous sub-tasks to children it supervises and handle failures of these children as appropriate. Depending on the nature of the requests, it may be best to create a new child for each request, which simplifies state management for collecting the replies. This is known as the “Error Kernel Pattern” from Erlang.

So the phrase you talking about means that these actors are the "last line of defence" from errors in your supervision hierarchy, so they should be strong and powerful guys (commandos) instead of some weak workers. And the less commandos you have - the easier it would be managing them and avoid mess at the top-level. Precisely saying, the count of commando's should be near to the count of business protocols you have (moving to the superheroes - let's say one for IronMan, one for Hulk etc.)

This document also has a good explanation about how to manage blocking operations.

Speaking of which

If an Actor isn't an appriote place to put code that has to block then what does satisfy the definition of "some special-cased thread

Actor definetely doesn't, because Akka guarantees only sequentiality, but your message may be processed on any thread (it just picks-up a free thread from the pool), even for single actor. Blocking operations are not recommended there (at least in same thread-pool with normal) because they may lead to performance problems or even deadlocks. See explanation for Spray (it's based on Akka) for instance : Spray.io: When (not) to use non-blocking route handling?

You may think of it like akka requires to interact only with asynchronous API. You may consider Future for converting sync to async - just send response from your database as a message to the actor. Example for scala:

 receive = { //this is receiving method onReceive
     case query: Query => //query is message safely casted to Query 
          Future { //this construction marks a peace of code (handler) which will be passed to the future 
            //this code will be executed in separate thread:
            doBlockingCallToJdbc(query)
          } pipeTo sender //means do `sender ! futureResult` after future's completion
     }
 }

Other approaches are described in the same document (Akka Doc)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!