[英]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.