Fork me on GitHub
Ben Sless06:12:15

What's the reason reduce is implemented as a function in core.async and not by the reduce interface or protocol?


Jo I thought I can call deref on a channel but I can't. didn't Rich mention this in a talk?

Ben Sless09:12:01

What does derefing a channel mean?

Ben Sless09:12:18

But deref shouldn't change the reference. You're just looking at it. Looking is free. Take mutates the channel

Ben Sless09:12:36

If channels had peek then it would be equivalent to deref

Ben Sless09:12:49

But why would you peek in a channel?


I see that makes sense. I wanted to use the timeout arg for deref. But I can do it with alts and timeout . Or use future I guess. The use case is doing work with a timeout

Ben Sless09:12:20

I've had a week of "how do I-s" turning into "what are you trying to do" So, what are you trying to do? Are you already building something with core async?


I have events and like to handle them async with a timeout. Doesn't matter so much if 1 piece of work fails it's more important that it keeps handling incoming stuff. I'm using a library that puts the events on a channel so there is core.async there. It's something like 1/second

Ben Sless09:12:30

Even when you time something out, you can leak resources because you didn't cancel the process. You take stuff out of a channel, then process it with a timeout?

Ben Sless09:12:22

What sort of processing are you doing?

Ben Sless09:12:42

CPU? Http calls? DB queries?


http calls, db queries and more http callls


and sometimes waiting for http calls to return


I believe this was talked about at some point long ago but I don't think it has ever been implemented/released

Ben Sless10:12:18

you need a few things. For each of those, implement a cancellation mechanism, you need it anyway to avoid resource leaks. Then you can implement a uniform interface which times the task out and cancels it

👀 1

You can also put channels on channels


I've used that "pattern" when I need to keep processing things, and at the same time each event can have a timeout, retry, etc


like putting the channels returned by go into a channel? What can I then do with that?


It really depends on the use case and the specifics 🙂 I can write a wall of text here but it might only make it more confusing; Just a tool to keep in mind that is available, which might not be obvious, aka the fact that you can put channels on channels


yea I try keep it in mind :thumbsup:


I'd like to pass a control channel that stops a go-loop when I put :stop, alternatively when I close the channel. What is the usual pattern? If I do <! from the control channel it will park right? So is there always some alt going on?

(a/go-loop []
      control :stop
      (a/timeout 300) (do (prn "loop") (recur))))

  (a/>!! control :stop)
doing this now

Ben Sless14:12:32

do you also have an input channel from which you take the loop's inputs?

Ben Sless15:12:41

Then you should utilize the fact that taking from a closed channel returns nil. Instead of a signalling channel close the input

Ben Sless15:12:14

This lends itself to a very nice pattern of automatically cascading shutdown if you build everything with little workers


(loop []
    (let [data (a/<!! event-ch)]
      (when-not (= data :disconnect)
is it fine to have such a loop recuring forever when the channel closes or should it check nil?

Ben Sless15:12:23

Absolutely check for nil

👍 2

Yeah, if the loop becomes infinite I believe you'll hog a thread from the thread pool (not good)

Al Z. Heymer08:12:55

(loop [] (let [a b] ... (recur))) is not different to (loop [a b] ... (recur b)) . And of course there is go-loop

Ben Sless08:12:29

Not to shill my own library, this is just the pattern I believe should always be used when consuming from a channel: