如何在try子句中定义的对象上调用catch子句中的方法?

时间:2015-04-26 09:13:18

标签: scala

我正在try-catch块中创建一个redis pubsub客户端。在try块中,客户端初始化为回调以将消息转发到客户端。如果将消息发送到客户端时出现问题,则会抛出异常,在这种情况下,我需要停止redis客户端。这是代码:

try {
  val redisClient = RedisPubSub(
    channels = Seq(currentUserId.toString),
    patterns = Seq(),
    onMessage = (pubSubMessage: PubSubMessage) => {
      responseObserver.onValue(pubSubMessage.data)
    }
  )
}
catch {
  case e: RuntimeException =>
    // redisClient isn't defined here...
    redisClient.unsubscribe(currentUserId.toString)
    redisClient.stop()
    messageStreamResult.complete(Try(true))
    responseObserver.onCompleted()
}

问题是redis客户端val没有在catch块中定义,因为可能存在创建它的异常。我也无法将try-catch块移动到回调中,因为在回调中无法(我能找到)引用redisClient对象(this无法解析)。

要解决此问题,我将redisClient实例化为var块之外的try-catch。然后在try块内部,我停止客户端,并为redisPubSub var分配一个新的redisClient(如上所述)。这是一个丑陋的黑客,也容易出错(例如,如果真的 创建第二个客户端的问题,catch块将尝试在错误的对象上调用方法)。

是否有更好的方法来编写此代码,以便在尝试将消息发送到responseObserver时引发异常时,可以在redisClient上正确调用stop()

更新

我刚用承诺解决了这个问题。有没有更简单的方法?

1 个答案:

答案 0 :(得分:0)

如果在发送邮件时出现问题,则会调用该异常处理程序而不是。这是设置客户端的问题。这个SO answer讨论了在发送消息时处理错误。

至于引用客户端的回调,我认为您希望在创建客户端之后注册回调,而不是在创建时尝试传递回调。这是执行此操作的sample code from Debashish Ghosh

据推测,回调将在另一个线程中运行,因此如果它使用redisClient,则必须注意并发性。理想情况下,回调可以通过一些参数到达客户端对象。如果没有,那么使用volatile可能是解决这个问题的最简单方法,尽管我怀疑如果多次回调一次失败,你最终会遇到麻烦。或许使用演员管理客户端连接,正如Debashish所做的那样?