Fork me on GitHub
#yada
<
2017-02-23
>
danielcompton20:02:41

This is probably all due to a misunderstanding on my part. I have a resource:

(yada/resource
    (merge
      {:id       :deps.jars/index
       :produces "text/html"
       :methods  {:get {:response (fn [ctx]
                                    (dasync/chan->defferred
                                      (go
                                        (let [characters (async/<! (db/all-characters db/db))]
                                          (tmpl/app-template ctx
                                            [:section.container [:h3 "Recent deploys"]]
                                            [:section.container
                                             [:h3 "Characters"]
                                             (for [c characters]
                                               [:p "Character: " (:name c) " specialty " (:specialty c)])])))))}}
       }
      access-control))
If an exception is thrown here, Yada returns a 404, not a 500 as I would expect. I can see there are ways to explicitly set status codes, but I would assume that a 500 is more appropriate for a thrown exception?

danielcompton20:02:03

Hmm, doing more testing, if I throw a non-async exception I get a 500

malcolmsparks20:02:49

Hmm. Are you possibly returning nil? That triggers a 404, it's somewhat of a yada pun.

danielcompton20:02:54

yeah I think that's the problem

danielcompton21:02:18

the go block is throwing, and it's being converted to a deferred, so the go block returns nil

danielcompton21:02:39

I was confused by the stack because I could see

danielcompton21:02:10

and I assumed that there was an exception being caught in there

danielcompton21:02:03

reading more closely I can see it's just a normal yada 404

danielcompton21:02:36

I think I'm probably going to narrowly tailor my core.async use and try to use manifold more.

mccraigmccraig21:02:43

i find manifold/Deferred's built-in error states make it a lot more convenient than core.async

stijn21:02:46

on the other hand, error handling on streams is really painful

mccraigmccraig21:02:37

you mean 'cos you can't use the error-state of the deferred returned by stream/take! @stijn ?

mccraigmccraig21:02:03

(or at least, if you can i couldn't figure out how to)

stijn21:02:42

yes, the stream just closes in case of an error thrown in e.g. stream/transform

mccraigmccraig21:02:13

yeah, i ended up doing the core.async thing and putting an exception on a stream as a value, which is kinda sucky

stijn21:02:17

well at least with core.async you can have a generic error handler do that, with transform, you have to wrap all your map / filter steps in error handling code

danielcompton21:02:10

For those following along at home, here's what I came up with:

{:response (fn [ctx]
                                    (d/let-flow [characters (dasync/chan->defferred (db/all-characters db/db))]
                                      (tmpl/app-template ctx
                                        [:section.container [:h3 "Recent deploys"]]
                                        [:section.container
                                         [:h3 "Characters"]
                                         (for [c characters]
                                           [:p "Character: " (:name c) " specialty " (:specialty c)])])))}

(defn throw-err [e]
  (when (instance? Throwable e) (throw e))
  e)

(defn chan->defferred
  "Converts a core.async channel (containing one value) into a deferred."
  [ch]
  (d/chain (stream/take!
             (stream/->source ch))
           throw-err))

mccraigmccraig21:02:32

you could also use core.async/take! to call deferred/success!

danielcompton21:02:20

I think I follow, would that also work for exceptions?

stijn21:02:44

deferred/error! for exceptions

danielcompton21:02:04

Thanks, is this correct?

(defn chan->deferred2
  "Converts a core.async channel (containing one value) into a deferred."
  [ch]
  (let [d (d/deferred)]
    (async/take! ch
                 (fn [v]
                   (if (instance? Throwable v)
                     (d/error! d v)
                     (d/success! d v))))
    d))

mccraigmccraig21:02:41

looks about right to me

danielcompton22:02:44

Awesome, thanks 🙂