了解play / scala错误处理

时间:2015-09-11 07:58:07

标签: scala error-handling playframework-2.0 try-catch

我在Scala / Play中使用Cassandra作为数据库的Web应用程序。我在测试潜在错误时遇到了以下问题。

以下是我项目的组成部分

  1. Application.scala - >基本控制器

  2. Model.scala - >持有     业务逻辑

  3. CassandraClient.scala - >连接的逻辑     cassandra并在cassandra上运行查询

  4. CassandraClient.scala如下所示

    object CassandraClient {
    
    private val cluster = Cluster.builder()
        .withLoadBalancingPolicy(
          new WhiteListPolicy(new RoundRobinPolicy(), nodes))
        .withSocketOptions(socketOptions)
        .addContactPointsWithPorts(nodes)
        .withCredentials(CASSANDRA_USERNAME, CASSANDRA_PWD).build()
    }
    
     private val session = cluster.connect()
    
    def getValueFromCassandraTable(token:String) = {
     var query = QueryBuilder.select.all()...
     seesion.execute(query)
    }
    

    当我第一次调用getValueFromCassandraTable时,首先建立了Cassandra连接。由于CassandraClient是一个Object,连接到Cassandra的逻辑只被调用一次。

    Model.Scala有一些代码来处理session.execute返回的未来。

    例如:在Model.scala中查看下面的示例代码。

        def getTitles(titles: String)(implicit ctxt: ExecutionContext): Future[List[<Sometype>]] = {
            try{
                CassandraClient.getValueFromCassandraTable(token).toScalaFuture.map { rows =>
                      rows.map(row => row("value").toList
                    }.recover { case e: Exception =>List()}
                  }
            } catch{case e:Exception => 
               Logger.info("THIS DOES NOT EXECUTE??")
               Future{List()}}
        }
    

    现在,当第一次执行上面的示例代码时,session.execute()会被执行。然后执行getValueFromCassandraTable。 所以我认为执行的流程是 Models.scala上面的代码片段 - &gt; session.execute() - &gt; getValueFromCassandraTable()

    因此,如果session.execute失败,我应该能够在try catch异常块中捕获它。但令我惊讶的是,当session.execute失败时,不会执行catch块。相反,play框架会引发异常。有人可以解释这种行为。

    异常堆栈

    Caused by: java.lang.RuntimeException: java.lang.ExceptionInInitializerError
        at play.api.mvc.ActionBuilder$$anon$1.apply(Action.scala:498) ~[play_2.10-2.4.2.jar:2.4.2]
        at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4$$anonfun$apply$5.apply(Action.scala:105) ~[play_2.10-2.4.2.jar:2.4.2]
        at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4$$anonfun$apply$5.apply(Action.scala:105) ~[play_2.10-2.4.2.jar:2.4.2]
        at play.utils.Threads$.withContextClassLoader(Threads.scala:21) ~[play_2.10-2.4.2.jar:2.4.2]
        at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4.apply(Action.scala:104) ~[play_2.10-2.4.2.jar:2.4.2]
        at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4.apply(Action.scala:103) ~[play_2.10-2.4.2.jar:2.4.2]
        at scala.Option.map(Option.scala:145) ~[scala-library-2.10.5.jar:na]
        at play.api.mvc.Action$$anonfun$apply$1.apply(Action.scala:103) ~[play_2.10-2.4.2.jar:2.4.2]
        at play.api.mvc.Action$$anonfun$apply$1.apply(Action.scala:96) ~[play_2.10-2.4.2.jar:2.4.2]
        at play.api.libs.iteratee.DoneIteratee$$anonfun$mapM$2.apply(Iteratee.scala:741) ~[play-iteratees_2.10-2.4.2.jar:2.4.2]
    Caused by: java.lang.ExceptionInInitializerError: null
        at models.Model$.getTitles(Model.scala:121) ~[classes/:na]
        at models.Model$.getMatchingTitles(Model.scala:48) ~[classes/:na]
        at models.Model$.getMatchingTitles(Model.scala:56) ~[classes/:na]
        at controllers.Application$$anonfun$searchTitle$1.apply(Application.scala:15) ~[classes/:na]
        at controllers.Application$$anonfun$searchTitle$1.apply(Application.scala:15) ~[classes/:na]
        at play.api.mvc.ActionBuilder$$anonfun$async$1.apply(Action.scala:456) ~[play_2.10-2.4.2.jar:2.4.2]
        at play.api.mvc.ActionBuilder$$anonfun$async$1.apply(Action.scala:456) ~[play_2.10-2.4.2.jar:2.4.2]
        at play.api.mvc.Action$.invokeBlock(Action.scala:533) ~[play_2.10-2.4.2.jar:2.4.2]
        at play.api.mvc.Action$.invokeBlock(Action.scala:530) ~[play_2.10-2.4.2.jar:2.4.2]
        at play.api.mvc.ActionBuilder$$anon$1.apply(Action.scala:493) ~[play_2.10-2.4.2.jar:2.4.2]
    Caused by: com.datastax.driver.core.exceptions.AuthenticationException: Authentication error on host /10.65.5.44:9042: Username and/or password are incorrect
        at com.datastax.driver.core.Connection$8.apply(Connection.java:368) ~[cassandra-driver-core-2.1.6.jar:na]
        at com.datastax.driver.core.Connection$8.apply(Connection.java:338) ~[cassandra-driver-core-2.1.6.jar:na]
        at com.google.common.util.concurrent.Futures$ChainingListenableFuture.run(Futures.java:861) ~[guava-16.0.1.jar:na]
        at com.google.common.util.concurrent.MoreExecutors$SameThreadExecutorService.execute(MoreExecutors.java:297) ~[guava-16.0.1.jar:na]
        at com.google.common.util.concurrent.ExecutionList.executeListener(ExecutionList.java:156) ~[guava-16.0.1.jar:na]
        at com.google.common.util.concurrent.ExecutionList.execute(ExecutionList.java:145) ~[guava-16.0.1.jar:na]
        at com.google.common.util.concurrent.AbstractFuture.set(AbstractFuture.java:185) ~[guava-16.0.1.jar:na]
        at com.datastax.driver.core.Connection$Future.onSet(Connection.java:1170) ~[cassandra-driver-core-2.1.6.jar:na]
        at com.datastax.driver.core.Connection$Dispatcher.channelRead0(Connection.java:1000) ~[cassandra-driver-core-2.1.6.jar:na]
        at com.datastax.driver.core.Connection$Dispatcher.channelRead0(Connection.java:922) ~[cassandra-driver-core-2.1.6.jar:na]
    

    Modle.scala中的Lin#121是一个调用CassandrClient.getValueFromCassandraTable的人。 我通过传递连接到cassandra的错误密码来模仿异常,因此获得AuthroizationException。我希望在Try catch中捕获此异常。但它没有被抓住。

    (请注意,这与Future无关,因为当异常发生时甚至没有调用session.executAysnc。所以期货尚未发挥作用。)

    - 编辑 -

    看起来Play正在吞噬Exception并抛出一个Error对象。不知道为什么会这样。

2 个答案:

答案 0 :(得分:1)

session.execute()可能会因IOError之类的错误而失败。你只能抓住异常。

Exception hierarchy

检查您是否没有错误,只是琐碎的异常。如果你要在你的问题中添加堆栈跟踪,那就太好了。

您可以尝试捕获任何Throwable(不要在实际项目中执行,您只能在调试时尝试)

try {
  .... your code ...
} catch {
  case _ => errorHandler(e)
}

只有在未来的情况下它才会捕获错误。

修改

我的cassandra数据库上的实例。 它在连接到cassandra期间出现异常时显示用户列表或“出错”字符串。例如,错误的节点或cassandra正在关闭。

    package controllers

    import com.datastax.driver.core.Cluster
    import com.datastax.driver.core.Session
    import scala.collection.JavaConversions._

    import play.api._
    import play.api.mvc._

    class Application extends Controller {

      def index = Action {
        try{
          var b = new StringBuilder
          for (row <- CassandraClient.getValueFromCassandraTable()) {
            b ++= row.getString("user_id")
            b ++= "\n"
          }
          Ok(b.toString())
        } catch {
          case _ => InternalServerError("something going wrong")
        }
      }

    }

    object CassandraClient {
       private val cluster = Cluster.builder()
        .addContactPoint("localhost")
        .withPort(9042)
        .build()

      val session = cluster.connect()

      def getValueFromCassandraTable() = {
        session.execute("SELECT * FROM mykeyspace.users")
      }
    }

答案 1 :(得分:0)

也许你有InterruptedException

例如代码不打印&#34; InterruptedException test&#34;如果你不使用Await。

 try {
   val exception = Future {
     throw new InterruptedException("exception")
   }.recover { case e: Exception => "ok" }

  exception.onComplete {
    case Success(a) => println(a)
    case Failure(err) => println(err)
  }
  //Await.result(exception, 1 seconds) 

 } catch {
   case e: Exception => println("InterruptedException test")
 }