Ah, thanks for pointing that out. I must've overlooked your example, because I'd already written off futures.
It seems like what you are suggesting, catch and print, might be about as good as I could hope for. If I don't want to block the main thread, then I don't see what else I could possibly do but print the exception. I guess I could store it somewhere, but in any case, I'd use this same pattern. Thanks, Justin. On Saturday, January 2, 2021 at 1:44:55 PM UTC-8 noise...@gmail.com wrote: > to be clear, in my second example you see the error from the future > without using deref > > good luck finding your solution > > On Sat, Jan 2, 2021 at 12:50 PM Austin Haas <aus...@pettomato.com> wrote: > >> 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 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/8dd61a48-0195-4b2d-bbee-7d24f976268fn%40googlegroups.com >> >> <https://groups.google.com/d/msgid/clojure/8dd61a48-0195-4b2d-bbee-7d24f976268fn%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/82e8cba4-c8a3-4d9a-81be-f703d8e0aa52n%40googlegroups.com.