Thank you very much for the explanation, Justin. I don't see how I can use futures, though, without blocking on the main thread (to get the exception when it occurs). I'm spawning a long-running process that never returns a value. On Saturday, January 2, 2021 at 12:43:14 AM UTC-8 noise...@gmail.com wrote:
> By the time the exception is caught, you are already outside the context > of the Thread which the repl client is interacting with. The default > exception handler has no information tying the executing thread to the repl > process (not to mention the dynamic variables clojure is using to associate > output from code your client runs with that socket connection). > > You probably don't want to rebind the root exception handler to show *all* > exceptions to your client socket. Which means that you need to set up some > soft of infrastructure connecting the information about the failed function > to the socket you are listening to. > > I find "future" very convenient for this, it uses a pool which will > perform better than creating Threads ad-hoc, and will capture Exceptions > and re-throw when you deref (of course, it's up to you to ensure you deref, > or use try/catch and otherwise forward the failure information via the > catch block). Also, it conveys dynamic bindings for things like > clojure.core/*out* and clojure.core/*err* that java classes don't know > about. > > (ins)user=> (def fut (future (throw (Exception. "oops")))) > #'user/fut > (ins)user=> @fut ; waits until deref to raise the error > Execution error at user/fn (REPL:11). > oops > (ins)user=> (def fut2 (future (try (throw (Exception. "oops")) (catch > Exception e (println "wat\n" e))))) ; prints instead of raising > #'user/fut2 > user=> wat > #error { > :cause oops > :via > [{:type java.lang.Exception > :message oops > :at [user$fn__165 invokeStatic NO_SOURCE_FILE 13]}] > :trace > [[user$fn__165 invokeStatic NO_SOURCE_FILE 13] > [user$fn__165 invoke NO_SOURCE_FILE 13] > [clojure.core$binding_conveyor_fn$fn__5754 invoke core.clj 2030] > [clojure.lang.AFn call AFn.java 18] > [java.util.concurrent.FutureTask run FutureTask.java 264] > [java.util.concurrent.ThreadPoolExecutor runWorker > ThreadPoolExecutor.java 1128] > [java.util.concurrent.ThreadPoolExecutor$Worker run > ThreadPoolExecutor.java 628] > [java.lang.Thread run Thread.java 834]]} > > > > On Thu, Dec 31, 2020 at 1:48 PM Austin Haas <aus...@pettomato.com> wrote: > >> >> Problem: When I connect to a socket server and create a thread, >> exceptions in the thread are printed in the server's process, not the >> client's. I'd like them to appear in the client's process, where the thread >> was created. >> >> (I'm using the term "process" very generally here, because I don't >> understand what is going on.) >> >> From searching, I understand that there are some other things at play, >> like System/err, but I don't understand what is happening or how I can work >> around it. Why does an exception thrown in the client process show in the >> client process, but an exception thrown in a thread created by the client >> process shows in the server process? Why doesn't binding *err* in a thread >> seem to have any effect? Any suggestions or workarounds? >> >> I'm not using futures, because this is a long-running process that never >> returns a value. >> >> Example transcript: >> >> # Socker server >> >> (The only command entered is the first one, which begins with clj. >> Everything after "user=>" is due to the client below.) >> >> $ clj -J-Dclojure.server.myrepl='{:port >> 5555,:accept,clojure.core.server/repl}' >> Clojure 1.10.1 >> user=> My second message. >> Exception in thread "Thread-0" clojure.lang.ExceptionInfo: My second >> exception {} >> at user$eval5$fn__141.invoke(NO_SOURCE_FILE:7) >> at clojure.lang.AFn.run(AFn.java:22) >> at java.lang.Thread.run(Thread.java:745) >> Exception in thread "Thread-1" clojure.lang.ExceptionInfo: My third >> exception {} >> at user$eval144$fn__145.invoke(NO_SOURCE_FILE:16) >> at clojure.lang.AFn.run(AFn.java:22) >> at java.lang.Thread.run(Thread.java:745) >> >> # Client >> >> $ nc localhost 5555 >> user=> (println "My first message.") >> My first message. >> nil >> user=> (throw (ex-info "My first exception." {})) >> Execution error (ExceptionInfo) at user/eval3 (REPL:2). >> My first exception. >> user=> (.start >> (Thread. >> (fn [] >> (println "My second message.") >> (throw (ex-info "My second exception" {}))))) >> nil >> user=> (.start >> (Thread. >> (let [out *out* >> err *err*] >> (fn [] >> (binding [*out* out >> *err* err] >> (println "My third message.") >> (throw (ex-info "My third exception" {}))))))) >> nil >> My third message. >> >> Any clues would be appreciated. Thanks! >> >> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send email to clo...@googlegroups.com >> Note that posts from new members are moderated - please be patient with >> your first post. >> To unsubscribe from this group, send email to >> clojure+u...@googlegroups.com >> For more options, visit this group at >> http://groups.google.com/group/clojure?hl=en >> --- >> You received this message because you are subscribed to the Google Groups >> "Clojure" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to clojure+u...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/clojure/d084b0c0-0a1b-4db2-95a1-f38ff894bfa6n%40googlegroups.com >> >> <https://groups.google.com/d/msgid/clojure/d084b0c0-0a1b-4db2-95a1-f38ff894bfa6n%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/clojure/8dd61a48-0195-4b2d-bbee-7d24f976268fn%40googlegroups.com.