【问题标题】:How to call a method in a catch clause on an object defined in a try clause?如何在 try 子句中定义的对象上调用 catch 子句中的方法?
【发布时间】:2015-04-27 21:57:01
【问题描述】:

我正在 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 实例化为vartry-catch 块之外。然后在try 块内,我停止客户端并将新的redisPubSub(如上创建)分配给redisClient var。这是一个丑陋的 hack,也容易出错(例如,如果创建第二个客户端确实存在 问题,catch 块将尝试调用错误对象上的方法)。

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

更新

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

【问题讨论】:

  • 由于 try 子句中的唯一表达式是您的 RedisPubSub 实例化,因此如果发生异常,我看不出您如何在 redisClient 上调用方法。如果抛出异常,则redisClient 变量为空。
  • @LomigMégard 这就是我的问题的重点,不是吗。如果由于接收消息的错误而导致运行时异常,我想关闭客户端,但我无法获得对变量的引用,因为初始化它时也可能引发异常。

标签: scala


【解决方案1】:

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

至于引用客户端的回调,我认为您希望在创建客户端之后注册回调,而不是在创建时尝试传递回调。这里有一些 sample code from Debashish Ghosh 可以做到这一点。

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

【讨论】:

  • 我写的代码有效。我尝试实例化客户端,然后传递回调,但客户端是一个案例类,回调是不可变的。我认为我不需要使用演员,因为我正在为我的服务器的每个客户端创建一个 redis 客户端,所以一切都是不可变的。我没有在不同线程之间共享 redis 客户端。此外,我正在使用的库(rediscala)在幕后使用演员。您可能是正确的关于未调用异常处理程序,我会更深入地挖掘,谢谢。
猜你喜欢
  • 1970-01-01
  • 2016-05-08
  • 2016-11-25
  • 1970-01-01
  • 2013-04-15
  • 2012-04-24
  • 2017-09-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多