Thanks for the awesome feedback.

On Saturday, December 29, 2012 9:57:56 AM UTC-5, Adam Clements wrote:
>
> Hey,
>
> I really like the idea of pulling out exception handling from the function 
> bodies. The try catch form has always bugged me a little bit.
>
> One thing that worries me though. While this is fine for examples where 
> you simply log the exception and move on, what if you need to do something 
> more complicated with the actual data? Say for example you need to 
> queue/trigger a retry, you no longer have your local bindings to work with 
> so you'd have to go back to a normal try/catch (disclaimer - didn't read 
> the paper, just going off the code and your comments)
>

I agree. There's certainly cases where the handler will want to restart the 
task and need access to the original bindings. I'll tinker around with a 
clean way to do this. Open for suggestions. 

>
> Couple of thoughts on the code:
>
> If you want to attach the error handlers to a particular function var 
> (task), why not alter-meta and add the handler function there rather than 
> maintaining a separate atom? Given that the deftask is pretty much 
> redundant anyway, I don't really see the point in making the distinction. 
>  Plus I think your current code is dropping namespaces, causing potential 
> future explosions?
>

Correct, deftask is redundant. I wanted more language to be able to talk 
about what a task is though. This might not be necessary due to what you 
said below this. Also, can you give an example of dropping namespaces?  I 
don't think I see where this happens, but I'm sure it's present. 

>
> I'd be tempted to make a supervise function which simply takes a handler 
> map and do away with the macros altogether, you can still def handlers at 
> the top level if you want to re-use them, but you could also merge sets of 
> handlers if you wanted, or pass in handlers which have some idea of what 
> task you're supervising because they have been declared in the same lexical 
> scope, e.g.
>
> (let [currenturl "..."] 
>    (supervise {ConnectionError (fn [e] (queue-retry! currenturl))
>                NotFoundError   (fn [e] (log "failed:" currenturl 
> (.getMessage e))}
>               fetch-url currenturl :timeout 10))
>
> or your example would look like:
> (defn divider [a b]
>    (/ a b))
>
> (def div-zero-handler 
>     {ArithmeticException (fn [e] (println "Cannot divide by zero"))})
>
> (def npe-handler
>     {NullPointerException (fn [e] (println "..."))})
>
> (def supervised-divider (partial divider (merge div-zero-handler 
> npe-handler)))
>
> (supervised-divider 10 0)...
>
> Which I would argue is a lot more idiomatic and flexible. I think macros 
> are overkill and unnecessary complexity here, you just need a supervise 
> function which takes responsibility for catching errors and lets you re-use 
> handlers
>
> Adam
>

Joe's paper (for reference 
http://www.erlang.org/download/armstrong_thesis_2003.pdf), in section 4.3.2 
on page 106 states that the goals are:

1. *Clean separation of issues*.
Dire achieves this by total separation of worker logic and supervisor 
logic. (IE "let it crash")

2. *Special processes only for error handling*.
Dire does not have this. Erlang processes aren't OS processes, but they are 
strongly isolated. These handlers that we set up in Dire have to be more 
resilient. I'm not sure how to do this at the moment.

3. *Workers can be run on different physical machines*.
Dire does not have this. Drawing on more knowledge from the Language of the 
System, what if we put queues between supervisors and workers? Is this 
worth it? I'm curious if you guys think it's a good idea for this 
environment.

4. *Error processing code becomes generic*.
To some degree Dire has this. The functions bound to defhandler can be 
reused.

I'm not comfortable with axing defhandler because I wanted this to feel 
like multimethods. I think it's a good idea for users of the supervise 
function to call their worker/task function and away it goes. If a new 
handler is defined, the map passed to supervise has to be modified, which 
violates the Open/Closed principle. That said, if you fork it and give your 
approach a try, I'm sure we can further this idea in some respective.

>
> On Friday, December 28, 2012 7:14:34 PM UTC, Michael Drogalis wrote:
>>
>> Hey folks,
>>
>> After watching The Language of the System and being directed to Joe 
>> Armstrong's paper on error handling, I concurred that his approach is 
>> fantastic. I really wanted the same thing for more rudimentary operations, 
>> like file handling. So I wrote Dire 
>> https://github.com/MichaelDrogalis/dire
>>
>> The pros are of this are that error handling code is removed from 
>> application logic and it is not order complected.
>> The cons are that tasks are not as strongly isolated as they are in 
>> Erlang. Also, because it is so simple (16 lines),
>> there's no way for a supervisor to "restart" a child task. (Yet, I guess. 
>> Ideas?)
>>
>> Can such a thing be useful in a non-distributed environment? Or does this 
>> look like a hassle to use?
>>
>>
>>

-- 
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

Reply via email to