This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-02-29
Channels
- # announcements (6)
- # babashka (7)
- # beginners (24)
- # calva (2)
- # cider (21)
- # clj-kondo (49)
- # cljdoc (29)
- # clojure (56)
- # clojure-dev (2)
- # clojure-europe (15)
- # clojure-nl (6)
- # clojure-norway (27)
- # clojure-uk (3)
- # clojuredesign-podcast (6)
- # clojurescript (1)
- # conjure (1)
- # core-async (8)
- # cryogen (2)
- # cursive (6)
- # data-science (1)
- # datomic (12)
- # events (1)
- # fulcro (16)
- # graalvm (28)
- # hyperfiddle (2)
- # lambdaisland (4)
- # leiningen (20)
- # observability (1)
- # off-topic (24)
- # pathom (5)
- # pedestal (10)
- # portal (7)
- # practicalli (1)
- # reitit (5)
- # rewrite-clj (20)
- # shadow-cljs (18)
- # vim (8)
- # xtdb (9)
:large_green_circle: RESOLVED, not a bug I think, although a little awkward
Hello, I feel like I may have found a bug, but perhaps I'm just doing something wrong.
I have the following example code (in thread), and I would expect tap2
to process all 10 messages, but it seems to get stuck.
I think this is because the core.async/mult
code does not give up on taps that are closed after a put
was started, thus the put
in the implementation returns true AND the callback fn done
is never triggered.
(let [ch (a/chan)
mult (a/mult ch)
tap1 (a/chan)
_ (a/tap mult tap1)
tap2 (a/chan)
_ (a/tap mult tap2)
mk-worker (fn [description tap messages-to-accept]
(a/go-loop [messages-accepted 0]
(if (< messages-accepted messages-to-accept)
(do
(println description "accepted the message" (a/
(My) expected output:
=> nil
tap1 accepted the message 0
tap2 accepted the message 0
tap1 has stopped accepting messages
tap2 accepted the message 1
tap2 accepted the message 2
...
tap2 accepted the message 8
tap2 accepted the message 9
Actual output:
=> nil
tap1 accepted the message 0
tap2 accepted the message 0
tap1 has stopped accepting messages
tap2 accepted the message 1
Description about what the problem might be refers to this line https://github.com/clojure/core.async/blob/master/src/main/clojure/cljs/core/async.cljs#L468
(when-not (put! c val done)
(untap* m c))
If the channel c
gets closed after the put occurs, but before the async message really put, then the done
callback is never calledI think I can fix this by always making taps with channels with at least a buffer of 1, but want to 1. check my understanding, and 2. report it if it is infact incorrect.
There is a long standing bug with putting channel ops inside and
s and or
s in clojurescript, where channel operations won't be properly conditional, because in clojurescript those macros will sometimes expand in to calls to the js*
special form, which is opaque to the analysis the go
macro does. Not sure if that is what is happening here, but possibly relevant because of the take in the and
Ah, pardon me, that issue may have gotten fixed as of https://github.com/clojure/clojurescript/commit/927f221f8fc26a49db7d0dcfd1d70008a986fd8f
Thanks for the suggestion, I've updated the code since that was a bit funky anyway, but I still see the issue.
Reading the docs more closely, I think this is intended: > Logically closing happens after all puts have been delivered. Therefore, any blocked or parked puts will remain blocked/parked until a taker releases them. However it's a bit misleading given the mult docs > If a tap puts to a closed channel, it will be removed from the mult. In the example I can solve it by allowing the loop to continue until we've used and discarded everything from the channel.
(let [ch (a/chan)
mult (a/mult ch)
tap1 (a/chan)
_ (a/tap mult tap1)
tap2 (a/chan)
_ (a/tap mult tap2)
mk-worker (fn [description tap messages-to-accept]
(a/go-loop [messages-accepted 0]
(if (< messages-accepted messages-to-accept)
(do
(println description "accepted the message" (a/