Fork me on GitHub
#core-async
<
2015-10-22
>
hlship18:10:10

So, I sometimes have trouble, documenting in text, what a channel does.

hlship18:10:18

So I've started using the term "convey".

hlship18:10:45

A writer "puts". A reader "takes". A channel "conveys".

alexmiller18:10:56

well Rich almost always talks about channels as conveyer belts

hlship18:10:06

Example: "the channel conveys a single value, an integer". Or "the channel conveys a series of maps."

alexmiller18:10:20

I think take is complementary to put though

hlship18:10:32

Yep, but most documentation I see stumbles on this, or uses the term "contains" which is not very accurate.

hlship18:10:42

Woops, going too fast. Let me fix that.

hlship18:10:06

Should have just cut-n-pasted from my tweets.

annapawlicka19:10:18

Hello hello! Question about handling exceptions in a channel. I have some code that looks like this:

(defn get-something [id]
  (when-not (some #{id} permitted-ids)
    (throw (Exception. "my exception message")))
  (go
  ;; do some async stuff and return a channel with a result
))

(go (->> ids
        (map get-something)
        (async/merge)
        (async/into #{})
        (<!)))
The problem is that when exception is thrown inside the go block, it's being eaten, the channel is closed, and the process hangs because there's async/merge waiting. Does anyone have any suggestions on how to properly handle situation like this?

alexmiller19:10:03

have you tried... catching the exception? :)

annapawlicka19:10:11

i’d like to throw it simple_smile

alexmiller19:10:08

Tim Baldridge has demo'ed a variant of the go block that catches and rethrows over a channel (I don't remember all the details)

annapawlicka19:10:37

gonna google it, thanks!

alexmiller19:10:43

I'm pretty sure it's in his screencast series but is probably available in one of his repos somewhere

ghadi19:10:58

annapawlicka: i've found exceptions much less useful in an async context. An approach I've used it to turn the error directly into a map, close to the source

ghadi19:10:13

Throwable->map from 1.7 is useful

annapawlicka19:10:12

Ah yes, I’ve been reading that post too

alexmiller19:10:58

exceptions are fundamentally a way to handle problems across call stacks (which are broken apart into many ephemeral threads in an async architecture)

alexmiller19:10:28

(which is also why debugging async stuff is annoying :)

annapawlicka19:10:33

Ok, I’m just going to log an error and move on, seems like the simplest and clearest thing to do.

annapawlicka19:10:03

But it’s good to find out how other folks are handling exceptions

alexmiller19:10:49

you can also configure the default uncaught exception handler to log somewhere and that would handle this generically. not sure that's a great long-term strategy, but might be useful.

annapawlicka19:10:06

Interesting.. probably not the best solution for this scenario, but I didn’t know I could change the handler

alexmiller19:10:54

you can also do it on a per-thread basis but there is not really any way to get to the 42+ threads under go blocks

hlship20:10:31

I've had some success with the pattern of conveying either [exception] or [nil value], i.e.

(let [[exception result] (<! chan)]
    (if exception ...

hlship20:10:07

This is pretty close to how Node.js handles exceptions and the like, and is quite palatable using array deconstruction.

hlship20:10:12

There can certainly be an issue where use of core.async, especially go macro, can result in an exception in a thread, and none of your code is in the stack trace!

mccraigmccraig22:10:15

i've been using the either-t<channel> monad transformer from cats in all my async cljs code... it makes for some very clean async error handling

mccraigmccraig22:10:38

@danielcompton: there used to be an example on the cats doc site, but now it's all about the nifty applicative-do syntax http://funcool.github.io/cats/latest/#channel ... i'll see if i can put an example together tomorrow