繁体   English   中英

如何从clojure期货的错误中获得堆栈跟踪?

[英]How do I get stacktraces from errors in clojure futures?

我有一些非常独立的任务,我已经使用期货分拆了。 这些任务通过core.async / chan将某些事件传递回主应用程序,或者只是与数据库通信。

其中一些未来现在无声无息。 我的日志中没有堆栈跟踪,或者在std {out,err}上没有堆栈跟踪。 我已经尝试围绕期货所调用的fns中的代码

(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)))))

这是否表明我根本不应该使用期货? 我是否应该使用代理,即使不需要向这些代理发送任何消息?

该行为与Java Future非常相似。 在未来的块中,异常可能会被抛出并被捕获,并且行为与您期望的一样。 当没有捕获到异常时, Future无法在调用线程上重新抛出它。 它只在您实际获取其值时以ExecutionException形式ExecutionException 这对应于Clojure中的deref。

让我们创建一个抛出某些东西的函数:

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

如果我将来包装它,它可以正常工作:

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

所以你可以在deref上捕获这个异常:

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"

注意在这种情况下如何在deref之前在后台线程上发生错误时立即打印“Caught ya”。 然后在deref上返回catch块将来返回的值。

最重要的是,底线是 - 它的工作方式与Java期货几乎相同。

这个问题实际上是由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)))))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM