This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-09-17
Channels
- # announcements (17)
- # aws (2)
- # babashka (21)
- # beginners (67)
- # calva (19)
- # cider (29)
- # clara (3)
- # clj-kondo (6)
- # cljsrn (10)
- # clojure (140)
- # clojure-europe (164)
- # clojure-nl (3)
- # clojure-uk (8)
- # clojurescript (62)
- # conjure (7)
- # core-async (24)
- # cursive (21)
- # datomic (5)
- # docker (40)
- # emacs (14)
- # fulcro (25)
- # gratitude (1)
- # honeysql (6)
- # introduce-yourself (1)
- # jobs (1)
- # jobs-discuss (32)
- # juxt (7)
- # lsp (13)
- # minecraft (2)
- # off-topic (49)
- # pathom (24)
- # practicalli (8)
- # re-frame (18)
- # react (23)
- # remote-jobs (6)
- # reveal (2)
- # shadow-cljs (75)
- # tools-deps (7)
Hi! Is there a way to write a function that reads from a channel and works both when invoked from within a go block and when not? Now I have
(defn my-async-fn [tracking-channel message]
(if (clojure.core.async.impl.dispatch/in-dispatch-thread?)
(async/go (when-not (async/>! tracking-channel message)
(log/debug "Failed to send")))
(do
(when-not (async/>!! tracking-channel message)
(log/debug "Failed to send")))))
but it obviously relies on an impl. detail 😞It's a bit risky to have uncontrollable puts on channels. You can theoretically start throwing exceptions
sorry, what do you mean by uncontrollable puts?
You could have only this part
(async/go (when-not (async/>! tracking-channel message)
(log/debug "Failed to send")))
that returns a channel, and then if it’s inside a go-block read result with <!, or outside a go with <!!this is still fragile. Imagine the tracking channel is full but you still call your function, what happens?
The problem is if you call the function over 1024 you subscribe over 1024 pending puts on the channel and start getting exceptions
you have to provide some back pressure mechanism. One way to do it is to always return a go block and park on it
@UK0810AQ2 > One way to do it is to always return a go block and park on it yes that’s what I meant, so you can control if you park/block depending from where you are calling the fn
So the fn doesn’t need to know if it’s inside go or not, and it shouldn’t imo, that’s what channels are for, to communicate threads and go processes
Well, you shouldn't use >!!
inside a go-block, but if you push or pull from a channel inside a spawned logical process (i.e. go block or thread) you must provide some back pressure mechanism
Correct, I meant only the first branch of the if should be the whole fn, so the go block ch is the return of the fn
I think it depends on the context, but why not directly putting message in tracking ch on whenever you need to, either with >! or >!!?
Thanks a lot for the input! I need to process it 🙂 It is a while since I worked with Async...
In terms of backpressure, the concern is real. You can utilize https://clojuredocs.org/clojure.core.async/dropping-buffer https://clojuredocs.org/clojure.core.async/sliding-buffer https://clojuredocs.org/clojure.core.async/offer!!
Long story short, you always should have some policy/strategy what happens when there’s “too much stuff” inside your system and the system can’t keep up. For example, offer!
will only return true
if the offered value is successfully put onto the channel. When it does not return true
, you need to decide what to do: 1. Forget about the value? 2. Try again? 3. “Store” the value elsewhere, and try to process later? 4 Etc.
It all depends on the use case. Some things are OK to be best effort delivery (say, performance metrics); E-commerce transactions, less so.
Re: your question. Spawning an extra (go …) block just to write to a channel is not a good idea. It will not bring any benefit. Generally, outside of (go …) blocks use (put! …) and/or (offer! …) and use a backpressure strategy that works for you.
And btw, just noticed: Your question says “read from a channel” but from what I can tell, your function as written puts values onto the channel (I guess that would be a “write”? 🙂 ) In core.async lingo, the phrases “take values from a channel” and “put values onto a channel” are used more often to eliminate confusion. If you haven’t watched Rich Hickey’s talks on core.async, I highly recommend them.