As for the general use case, atoms and core.async are great tools, and I haven't needed to use refs (aka the STM) for years.
In addition to this, I personally find core.async to deal poorly with flow control (e.g. slow subscribers slowing down the entire flow for every subscriber), and seems to not have a lot of telemetry / it’s difficult to find out what’s going on in the thread pool behind it.
I’ve personally settled on Zach Tellman’s Manifold library, which provides a much more sane abstraction and is fully compatible with core.async.
For some addition thought and material on these topics, I highly recommend watching this talk by Zach, “Everything Will Flow” https://youtu.be/1bNOO3xxMc0
Agents also have a fixed thread pool, and you should use send-off if you intend to do I/O.
This is also a bit of a departure for people coming from Go or Erlang/Elixir.
It seems like there are a lot of parallels between agents and core.async.
Agents, like go blocks, run in a thread pool. Any blocking IO should be pushed off to a separate thread outside of the thread pool. In the case of agents, there is (send-off). In the case of core.async, there is (thread)
I mentioned in an edit that I realized core.async is a library. It's still first-party, so it's still somewhat idiomatic.
major issues list memory leaks. https://dev.clojure.org/jira/secure/IssueNavigator.jspa?rese...
first-party?
By first-party, I mean it seems to be officially part of the Clojure ecosystem, the docs are hosted on the main site: https://clojure.github.io/core.async/
It doesn’t mean it’s not production ready.
This is definitely a good high-level article, just something I was surprised by, since core.async is what drove me (and several other people I know) to start using Clojure.
EDIT: Just a note that I know core.async isn't built in, that was a mistake. It is a first-party library, however.