Scala Akka容错方法

Scala Akka容错方法,scala,akka,Scala,Akka,我正在尝试scala+Akka,我正在尝试找出容错性。我有一个actor,它接收来自主管的消息并将数据插入数据库。主管在参与者遇到故障时重新启动该参与者 我正在更改postRestart()中的连接字符串,以防数据库出现连接问题。现在,只要一个数据库存在连接问题,参与者就会重新启动并开始将数据插入另一个数据库 这是一个足够好的方法吗?推荐的方法是什么 主管: class SocialSupervisor extends Actor { override val supervisorSt

我正在尝试scala+Akka,我正在尝试找出容错性。我有一个actor,它接收来自主管的消息并将数据插入数据库。主管在参与者遇到故障时重新启动该参与者

我正在更改postRestart()中的连接字符串,以防数据库出现连接问题。现在,只要一个数据库存在连接问题,参与者就会重新启动并开始将数据插入另一个数据库

这是一个足够好的方法吗?推荐的方法是什么

主管:

class SocialSupervisor extends Actor {

    override val supervisorStrategy=OneForOneStrategy(loggingEnabled = false){
    case (e:Exception)=>Restart
    }

    val post_ref=context.actorOf(Props[Post])
    def receive={
            case Get_Feed(feed)=>{
                //get data from feed
                post_ref!Post_Message(posted_by,post)
            }
    }
}
演员:

class Post extends Actor{
  val config1=ConfigFactory.load()
    var config=config1.getConfig("MyApp.db")

    override def postRestart(reason: Throwable) {
        config=config1.getConfig("MyApp.backup_db")
        super.postRestart(reason)
    }

    def insert_data(commented_by:String,comment:String){
            val connection_string=config.getString("url")
                val username=config.getString("username")
                val password=config.getString("password")
                //DB operations
    }

    def receive={
      case Post_Message(posted_by,message)=>{
        insert_data(posted_by, message)
      }
    }
}

我认为您可以对代码进行一些改进,使其更具“容错性”

模块化

您可能应该将您的
insert_data
函数与Actor的其余部分分开,以便它可以独立于任何
Actor系统
进行使用和测试。您的参与者应该只有很少的代码,并且
receive
方法基本上应该是外部函数的分派器:

object Post {
  def insert_data(conn : Connection)(commented_by : String, comment : String) = {
    ...
  }
}
您甚至可以进一步删除
连接
依赖项。从参与者的角度来看,插入只不过是一个函数,它接收
PostMessage
,并返回有效行更新的数量:

object Post {
  //returns an Int because Statement.executeUpdate returns an Int
  type DBInserter : Post_Message => Int
现在,您可以像以前一样插入到数据库连接中:

  def insertIntoLiveDB(connFactory : () => Connection) : DBInserter = 
    (postMessage : Post_Message) => {
      val sqlStr = s"INSERT INTO .."
      connFactory().createStatement() executeUpdate sqlStr
    }
  }
或者编写一个函数,该函数从不为测试目的进行插入:

  //does no inserting
  val neverInsert : DBInserter = (postMessage : Post_Message) => 0
}
现在,您的演员几乎没有逻辑:

class Post(inserter : Post.DBInserter) extends Actor {

  def receive = {
    case pm : Post_Message => inserter(pm)
  }

}
容错性

到目前为止,应用程序中“错误”的最大来源是网络,在您的案例中,通过连接数据库来体现。我们需要一些方法,以便在出现故障时自动刷新连接。我们可以使用factory函数来执行此操作:

def basicConnFactory(timeoutInSecs : Int = 10) = {

  //setup initial connection, not specified in question
  var conn : Connection = ???  

  () => {
     if(conn isValid timeoutInSecs)
       conn
     else {
       conn = ??? //setup backup connection
       conn
     }
  }
}
现在,每次插入时都会测试连接的有效性,如果出现问题,则会重新建立连接。然后可以使用此工厂创建参与者:

import Post.queryLiveDB
val post_ref = 
  context actorOf (Props[Post], insertIntoLiveDB(basicConnFactory()))
随着您的生产要求越来越严格,您可以要求工厂使用