2013-04-24 57 views
6

我希望我的clojure程序有一个可以运行的脚本目录 - 这些脚本中的每一个都是我用加载文件执行的clojure代码。这将在未来发生,以便脚本在其自己的线程中运行。期货和加载文件中的异常处理

问题是我从来没有看到任何来自脚本的错误消息。如果脚本失败,则无法知道问题出在哪里。我认为这是因为在未来的线程中没有异常处理。我可以把异常处理成剧本,像下面,和它的作品:

;; script code  
(try 

(println (/ 10 0)) 

(catch Exception e 
    (println "Exception: " (.getMessage e)))) 

不过,我宁愿把异常处理从一个层面了,周围的负载文件,这样我不不得不在脚本本身中有异常处理:

(defn handleexes [f] 
    (try 
    (f) 
    (catch Exception e 
     (println "exception: " (.getMessage e))))) 

(defn start-script-play [name] 
    (println "starting script: " name) 
    (let [f (future (handleexes (load-file (str "./scripts/" name))))] 
    (swap! scripts (fn [s] (assoc s name f))))) 

所以我在调用手动加载文件。这不起作用 - 主要是。当我运行一个包含自己的异常处理程序的脚本时,它会工作,如上所述!没有脚本中的异常处理程序,什么都没有。奇怪的。

好吧,无论如何,所以我的问题是这里发生了什么?

  • 是例外,确实没有在期货中处理?
  • 为什么在加载文件中发生异常时不会捕获异常?
  • 如何在这种情况下捕捉异常?

回答

6

您看起来并没有取消您的示例中提及的期货(可能与deref@)。

如果在将来引发异常,试图取消引用该未来将导致java.util.concurrent.ExecutionException被抛出。这个例外将包裹将来抛出的任何东西。

(try 
    (future (/ 10 0)) 
    "done" 
    (catch Exception e 
    (str "caught " e))) 

;=> "done" 


(try 
    @(future (/ 10 0)) 
    "done" 
    (catch Exception e 
    (str "caught " e))) 

;=> "caught java.util.concurrent.ExecutionException: java.lang.ArithmeticException: Divide by zero" 
+0

有趣---但对我来说这是没有用的,因为我从来没有计划取消未来。我纯粹为副作用运行脚本,并且脚本可能会永久循环。在这种情况下,破坏未来的线程将永远阻止。我想我可以做出另一个未来来检查第一个未来!也许期货不是在这里使用的解决方案。 – Bzzt 2013-04-24 18:38:40

+4

在这种情况下,代理商可能会为您提供更多您要查找的内容。除其他外,它们允许您指定一个任意的错误处理程序。 http://clojure.org/agents – dfreeman 2013-04-24 18:55:56