簡體   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