I have a few tasks that are quite independent that I've spun off using futures. These tasks communicate certain events back to the main app over a core.async/chan, or just talk to the db.
Some of these futures are now failing silently. I get no stacktraces in my logs, or on std{out,err}. I've tried surrounding the code in the fns called by the futures with
(try (do-stuff)
(catch Exception e
(log/error e))
just to get some output into my logs, but that--surprisingly!--didn't work.
Is my only option to spin up yet another thread which does the following in a loop?
(let [m (Thread/getAllStackTraces)]
(doseq [e (.entrySet m)]
(log/error (.toString (.getKey e)))
(doseq [s (.getValue e)]
(log/error " " (.toString s)))))
Is this a symptom indicating that I shouldn't be using futures at all? Should I be using agents, even though there's no need to send any messages to these agents?
The behavior is very similar to Java Future
. Inside the future block exceptions may be thrown and caught, and that behaves as you would expect. When an exception is not caught, the Future
has no way of rethrowing it on the calling thread. It only does so in form of ExecutionException
when you actually get its value. This corresponds to deref in Clojure.
Let's create a function that throws something:
(defn die [] (throw (RuntimeException.)))
If I just wrap it in future, it works fine:
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
So you can catch this exception on deref:
user=> (def x (future (die)))
#'user/x
(try @x (catch Exception e (println "Caught ya")))
Caught ya
nil
Or you can catch it inside the future:
user=> (def x
#_=> (future
#_=> (try (die)
#_=> (catch Exception e
#_=> (print "Caught ya!")
#_=> "Something"))))
#'user/x
Caught ya
user=> @x
"Something"
Note how in this case it prints "Caught ya" immediately when the error occurs on the background thread, before deref. Then on deref it returns value returned by the catch block in future.
Once again, the bottom line is - it works pretty much the same as Java futures.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With