Thank you, Sean. That is an excellent example.

-austin

On Sunday, January 3, 2021 at 12:48:55 PM UTC-8 Sean Corfield wrote:

> Austin,
>
> You might find a macro like this helpful -- just use it directly instead 
> of future. You can replace println with whatever sort of logging you want.
>
> (defmacro logged-future
> "Given a body, execute it in a try/catch and log any errors."
> [& body]
> (let [line (:line (meta &form))
> file *file*]
> `(future
> (try
> ~@body
> (catch Throwable t#
> (println t# "Unhandled exception at:"
> ~file "line:" ~line
> "on thread:"
> (.getName (Thread/currentThread))))))))
>
>
> On Sat, Jan 2, 2021 at 5:59 PM Austin Haas <aus...@pettomato.com> wrote:
>
>> 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 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/82e8cba4-c8a3-4d9a-81be-f703d8e0aa52n%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/clojure/82e8cba4-c8a3-4d9a-81be-f703d8e0aa52n%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>
>
> -- 
> Sean A Corfield -- (904) 302-SEAN
> An Architect's View -- https://corfield.org/
> World Singles Networks, LLC. -- https://worldsinglesnetworks.com/
>
> "Perfection is the enemy of the good."
> -- Gustave Flaubert, French realist novelist (1821-1880)
>

-- 
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/dd43e7e7-c790-4613-8ab3-3172cb23b822n%40googlegroups.com.

Reply via email to