为什么这个try-catch包装器宏无法捕获异常?

Art*_*ldt 1 vmware clojure pallet

我有这个宏来捕捉一个特别讨厌的VMware bug(如果你重新连接就会消失)

(defmacro with-mib-workaround
  "this macro exists because vCenter sometimes fails to get the
managed object reference for objects that actually do exist. Wrap
any call to vi java in this to have it retry with an incramental delay"
  [& body]
  `((fn mib-workaround# [attempt# timeout#]
      (if (> attempt# 10)
        (do (println "giving up after too many mib-not-found failures")
            (println "please complain to VMware about this bug...")
            (throw (Exception. "MIB not found for existing object")))
        (try
          ~@body
          (catch com.vmware.vim25.ManagedObjectNotFound e#
            (println "Caught VMware ManagedObjectNotFound bug ")
            (sleep timeout#)
            (mib-workaround# (inc attempt#) (+ 5 timeout#))))))
    0 5))
Run Code Online (Sandbox Code Playgroud)

在repl中测试时,它可以工作:

(with-mib-workaround (throw (com.vmware.vim25.ManagedObjectNotFound.)))
Caught VMware ManagedObjectNotFound bug
Caught VMware ManagedObjectNotFound bug
Caught VMware ManagedObjectNotFound bug
Caught VMware ManagedObjectNotFound bug
Caught VMware ManagedObjectNotFound bug
Caught VMware ManagedObjectNotFound bug
Caught VMware ManagedObjectNotFound bug
Caught VMware ManagedObjectNotFound bug
Caught VMware ManagedObjectNotFound bug
Caught VMware ManagedObjectNotFound bug
Caught VMware ManagedObjectNotFound bug
giving up after too many mib-not-found failures
please complain to VMware about this bug...
nil
Run Code Online (Sandbox Code Playgroud)

当bug在实际运行中弹出时此代码:

(with-mib-workaround
      (relogin vm)
      (destroy vm)
      (clone vm)
      (start-vm vm)
      (sleep (* 4 60))))
Run Code Online (Sandbox Code Playgroud)

通过捕获落入权利

 Caused by: java.lang.RuntimeException: com.vmware.vim25.ManagedObjectNotFound
18:15:02    at com.vmware.vim25.mo.ManagedObject.retrieveObjectProperties(ManagedObject.java:158)  <---- CAUSED HERE
18:15:02    at com.vmware.vim25.mo.ManagedObject.getCurrentProperty(ManagedObject.java:179)
18:15:02    at com.vmware.vim25.mo.ManagedEntity.getName(ManagedEntity.java:99)
18:15:02    at sun.reflect.GeneratedMethodAccessor17.invoke(Unknown Source)
18:15:02    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
18:15:02    at java.lang.reflect.Method.invoke(Method.java:597)
18:15:02    at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:92)
18:15:02    at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:316)
18:15:02    at hello_pallet.vi$get_vm_by_name$fn__4253.invoke(vi.clj:51)
18:15:02    at clojure.core$filter$fn__3830.invoke(core.clj:2478)
18:15:02    at clojure.lang.LazySeq.sval(LazySeq.java:42)
18:15:02    at clojure.lang.LazySeq.seq(LazySeq.java:67)
18:15:02    at clojure.lang.LazySeq.first(LazySeq.java:82)
18:15:02    at clojure.lang.RT.first(RT.java:559)
18:15:02    at clojure.core$first.invoke(core.clj:55)
18:15:02    at hello_pallet.vi$get_vm_by_name.invoke(vi.clj:51)
18:15:02    at hello_pallet.vi$clone_vm.invoke(vi.clj:154)
18:15:02    at hello_pallet.core$clone.invoke(core.clj:136)
18:15:02    at  hello_pallet.core$fn__112$fn__113$mib_workaround__52__auto____114.invoke(core.clj:188)   <--- FALLS PAST HERE
18:15:02    at hello_pallet.core$fn__112$fn__113.invoke(core.clj:185)
18:15:02    at clojure.lang.AFn.applyToHelper(AFn.java:163)
18:15:02    at clojure.lang.AFn.applyTo(AFn.java:151)
18:15:02    at clojure.lang.AFunction$1.doInvoke(AFunction.java:29)
18:15:02    at clojure.lang.RestFn.applyTo(RestFn.java:137)
18:15:02    at clojure.core$apply.invoke(core.clj:602)
18:15:02    at pallet.action_plan$apply_action$fn__657.invoke(action_plan.clj:366)
Run Code Online (Sandbox Code Playgroud)

Mic*_*zyk 5

你的异常似乎被包裹在一个RuntimeException; 不久前,Clojure开始在RTE中包装所有已检查的异常.您必须捕获RuntimeException,解开原因 - (.getCause e)检查它是否属于instance?您的异常类并根据需要处理/重新抛出.

NB.我相信最近对异常故事做了一些修改,但是我不清楚地记得细节(如果你需要确切地知道发生了什么,我相信你可能想要四处搜寻"偷偷摸摸" - 关于ggroups和git日志).更新:请参阅此提交,其祖先和JIRA上的相关票证:CLJ-855:catch接收RuntimeException而不是预期的已检查异常.