core-async

flowthing 2025-04-29T10:54:26.448249Z

Why does the last >!! in this example never complete?

(require '[clojure.core.async :as async])

(def chan (async/chan 8))
(async/>!! chan :foo)
(async/<!! chan)

(future (async/<!! chan))
(future-cancel *1)

(async/>!! chan :bar) ; this put never completes
(count (.buf chan)) ;;=> 0
(async/<!! chan) ; blocks forever

2025-04-29T12:11:54.448089Z

your future call is still pending take!

2025-04-29T12:12:29.658669Z

so when you put :bar, it's consumed by that call

2025-04-29T12:12:47.113619Z

put another value, and you can take from it again

2025-04-29T12:13:00.075109Z

(future (a/<!! c))
(future-cancel *1)

(a/>!! c :foo)
(a/>!! c :bar)
(a/<!! c) ;; => :bar

flowthing 2025-04-29T12:36:18.621489Z

Hmm, right, thanks. So if I understand correctly, interrupting the thread doing the <!! aborts the take, but doesn't decrement the take counter of the channel, which is why core.async remains waiting for an additional put.

2025-04-29T12:37:29.390469Z

eh

2025-04-29T12:37:48.019039Z

conceptually okay, but not technically correct

2025-04-29T12:39:05.355079Z

when there is nothing in the channel to take, take handlers get put into a linked list. <!! then blocks on a promise waiting for its take to get called. what gets aborted is dereffing the promise. and yeah, interrupting a thread doesn't go back and remove that take from the linked list.

flowthing 2025-04-29T12:39:46.690699Z

That's helpful, thanks! Now I understand. 👍

👍 1
flowthing 2025-04-29T12:42:47.912439Z

(And yeah, I began thinking in terms of counters because I was playing around with the new Datafiable support on channels, which have :take-count and :put-count. 🙂 )

2025-04-29T16:41:44.316879Z

I don't think <!! is interruptible even no? Or maybe the underlying blocking queue is?

2025-04-29T16:42:39.107279Z

CountDownLatch#await

2025-04-29T16:45:12.612009Z

Ok, so that would throw an InterruptedException

2025-04-29T16:47:13.377249Z

I wonder if there's a way to catch it inside the future and clear the take ?

2025-04-29T16:47:53.400489Z

I don't know of any way to clear a take outside of mucking with channel internals

2025-04-29T16:49:02.080939Z

I feel it seems a bit of a "bug" to me. Or at least an undefined behavior. Because you'd expect<!! to properly handle interrupt. And maybe this is the semantic they want, like it doesn't actually cancel but will get interrupted.

2025-04-29T16:49:21.382809Z

But probably something internally to core.async you could fix.

2025-04-29T16:49:53.695149Z

yeah the only place to fix it would be inside core.async. probably in <!! itself.

2025-04-29T16:50:18.904919Z

I agree that the behavior caught me off guard.

jmv 2025-04-29T20:33:45.347439Z

does anyone have examples of otel tracing with flow? i realize this is very early on but i am curious how to set it up to track execution across procs.

ghadi 2025-04-29T20:35:47.426019Z

flow is pretty generic and doesn't necessarily presume a request-orientation

ghadi 2025-04-29T20:37:04.053109Z

you can do all the ordinary things that you need to do to convey a logical request for otel: add a map key representing the otel context object, flow (verb) that around

ghadi 2025-04-29T20:37:58.751729Z

Datomic's core update system is a flow (the noun) -- though it predates flow (the library) by 10+ years

ghadi 2025-04-29T20:38:48.265499Z

we have some otel instrumentation for dev purposes, you do all the normal things to connect bindings across thread boundaries

jmv 2025-04-29T20:39:55.152789Z

awesome, ty! i will explore and share back any examples i can

2025-04-29T20:59:42.641579Z

shameless plug, but if it is for dev tracing purposes there is https://github.com/flow-storm/flow-storm-async-flow-plugin