core-async

Nim Sadeh 2025-04-07T20:25:07.331789Z

Is there a generalized pattern for dealing with exceptions in go blocks? As I see it, I have three options: 1. carefully bubble up exceptions until I leave the async context then throw it 2. Use an exception chan that I pass around my async architecture, listen to it at the top, and handle when I get something out of it 3. Catch exceptions near the call site of exception-throwing functions, convert them into non-exceptional but meaningful values, and write code on every go block in the architecture that accounts for these values I would be glad to write up a writeup on this with some input because I think it's a murky but useful concept but I don't think I have all the answers here

2025-04-07T20:34:58.508749Z

how you do this is going to depend a lot on what "style" you are using for async operations: 1. future like 2. service like future like implies you want something to have as similar as possible behavior to just calling a function, so @(future (+ 1 2)) will call + on another thread and block waiting for the result and rethrow exceptions. a function call shares the stack so people naturally want exceptions to "bubble" across contexts here. server like is as if some component was a separate long running service that you interact with by exchanging messages. the model here doesn't share a stack, so exceptions bubbling makes less sense, a service would report its own errors (logging. metrics or whatever) and maybe send back an error message.

2025-04-07T20:36:04.454879Z

I like to see the service like pattern, I think it plays to core.async's strengths, but it seems like the future like pattern is more common

2025-04-07T20:38:04.242819Z

there are libraries that add exception bubbling on top of channel operations https://github.com/k13labs/futurama/ for example

πŸ‘€ 1
Nim Sadeh 2025-04-07T20:41:28.715679Z

I think my streaming work is more service oriented. I'm trading messages between long-running processes that execute actions. I pass a stream to the SSE endpoint

Alex Miller (Clojure team) 2025-04-07T21:08:01.707099Z

I broadly agree with @hiredman’s take on this https://clojure.github.io/core.async/flow.html, the upcoming extension to core.async (not yet out) is explicitly the service context and flows have a standard exception channel that all services forward exceptions to (if they can't/don't handle them themselves) - that's kind of set up for you when you create a flow

😲 1
πŸ™Œ 1
Nim Sadeh 2025-04-07T23:31:18.405129Z

Is there something in flow about preventing/debugging deadlocks?

Alex Miller (Clojure team) 2025-04-07T23:49:32.788529Z

Depends what you mean about deadlocks. Flow will let you ping processes to see their state and monitor the channels between them, so that would probably help debug if things are somehow blocked

2025-04-08T04:42:02.047299Z

I guess typically, you're meant to try/catch inside the Go block. That's really the answer here. Now, how to handle the catch inside the Go, is what others have said.

2025-04-07T03:30:41.717599Z

Given the latest changes, what should I expect would be the handling for JDK 21? Will go blocks now use vthreads?

2025-04-07T20:22:31.185399Z

I mean, if you are doing compute that is going to take 30+ seconds, it locks up the thread during that whole time. You were not supposed to do that on the go pool before, and similarly you're not supposed to use a vthread in those cases because it pins the OS thread.

2025-04-07T04:09:33.589479Z

I see that it seems like it defaults to :io optimized, but now it looks like all are just a cached thread pool. So does the go block now just use an unbounded thread pool same as thread ?

2025-04-07T04:10:57.212939Z

And when exactly would you receot :compute and :mixed ? Does thread now become :compute, io-thread becomes :io and go becomes :mixed ?

Alex Miller (Clojure team) 2025-04-07T04:47:04.550609Z

We have not yet made any changes to use vthreads, those are still coming. In the current release, all pools are cached thread pools. thread has been available for :mixed and will continue to have those semantics. We are not adding any construct for compute - just use normal threads (the :compute pool will be used for async flow).

2025-04-07T04:52:45.646539Z

I see, compute is for light compute like async flow, I assumed it was for heavy compute.

Alex Miller (Clojure team) 2025-04-07T04:53:48.862149Z

I dont know what distinction is supposed to mean

Alex Miller (Clojure team) 2025-04-07T04:54:30.519059Z

Compute as hard as you want :)

πŸ˜› 1
Alex Miller (Clojure team) 2025-04-07T04:55:49.381309Z

The point is you’re bound to a platform thread and not doing blocking io