我该如何从Clojure futures中获取错误的堆栈跟踪?

6
我有几个相当独立的任务,我使用 futures 将它们拆分。这些任务通过 core.async/chan 与主应用程序通信,或者只是与数据库交互。
现在有一些这些 futures 在默默地失败。我的日志中没有堆栈跟踪信息,也没有在 std{out,err} 上看到任何信息。我尝试过将 futures 调用的函数代码包围在...中。
(try (do-stuff)
  (catch Exception e
    (log/error e))

我希望能够在我的日志中得到一些输出,但出人意料的是,这并没有起作用。

那么,我的唯一选择是启动另一个线程,在循环中执行以下操作吗?

(let [m (Thread/getAllStackTraces)]
    (doseq [e (.entrySet m)]
      (log/error (.toString (.getKey e)))
      (doseq [s (.getValue e)]
        (log/error " " (.toString s)))))

这是一个症状,表明我根本不应该使用futures吗?即使不需要给这些代理发送任何消息,我是否应该使用代理?


1
我不熟悉core.async,所以无法评论您在该库中使用futures的适当性。但是,如果future由于异常而失败,则取消引用future应重新抛出异常。 - Alex
2个回答

8

这种行为与Java Future非常相似。在future块中可能会抛出和捕获异常,并且其行为与您预期的一样。当未捕获异常时,Future无法在调用线程上重新引发它。只有在实际获取其值时,它才以ExecutionException的形式执行此操作。这对应于Clojure中的deref。

让我们创建一个抛出异常的函数:

(defn die [] (throw (RuntimeException.)))

如果我将它包装在“future”中,它就可以正常工作:

user=> (def x (future (die)))
#'user/x
; Note: No exception here
user=> @x
RuntimeException   user/die (NO_SOURCE_FILE:1)
; Bam! Exception thrown on deref, think of it as
; ExecutionException when getting failed future's value in Java

所以你可以在解除引用时捕获此异常:
user=> (def x (future (die)))
#'user/x
(try @x (catch Exception e (println "Caught ya")))
Caught ya
nil

或者你可以在未来内部捕获它:

user=> (def x 
  #_=>   (future 
  #_=>     (try (die)
  #_=>       (catch Exception e
  #_=>         (print "Caught ya!")
  #_=>         "Something"))))
#'user/x
Caught ya
user=> @x
"Something"

请注意,当在后台线程上发生错误并在dereferencing之前立即打印"Catch ya"时,它打印出了本例中的内容。然后,在dereferencing时,它返回由catch块在future中返回的值。
再次强调,它与Java futures基本上是相同的。

0

这个问题实际上由 Stuart Sierra 在这里 解决。去那里阅读,因为它值得一看。简而言之,他的优雅解决方案是设置默认未捕获异常处理程序:

;; Assuming require [clojure.tools.logging :as log]
(Thread/setDefaultUncaughtExceptionHandler
  (reify Thread$UncaughtExceptionHandler
    (uncaughtException [_ thread ex]
      (log/error ex "Uncaught exception on" (.getName thread)))))

1
这对期货仍然有效吗?根据文章:“另一个问题是:future内部的异常总是被Future捕获。除非有东西调用Future.get(在Clojure中解除引用),否则异常不会被抛出。” - KendallB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接