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 [email protected] 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 <[email protected]> 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 [email protected]
>> Note that posts from new members are moderated - please be patient with
>> your first post.
>> To unsubscribe from this group, send email to
>> [email protected]
>> 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 [email protected].
>> 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 [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
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 [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/clojure/8dd61a48-0195-4b2d-bbee-7d24f976268fn%40googlegroups.com.