My experience with Structured Concurrency

David Alayachew davidalayachew at gmail.com
Fri Aug 15 18:44:31 UTC 2025


Sure.

Long story short, the biggest reason why STS is so useful for me is because
it allows me to fire off a bunch of requests, and handle their failures and
outcomes centrally. That is the single most useful feature of this library
for me. It's also why Future.status was not so useful for me -- it calls
get under the hood, and therefore might fail! Handling that was too much
scaffolding.

So, when someone recently challenged me to use Joiners (rather than the old
STS preview versions I was used to), I started creating Joiners to handle
all sorts of failure and outcomes. At first, a lot of them could be handled
by the Joiner.awaitUntil(), where I would just check and see if the task
failed, then handle the error. But as I got further and further along, I
started needing to add state to my Joiners in order to get the failure
handling that I wanted. For example, if a certain number of timeouts occur,
cancel the scope. Well, that necessitates an AtomicNumber.

Then, as the error-handling got more and more complex, I started finding
myself making a whole bunch of copy paste, minor variations of similar
Joiners. Which isn't bad or wrong, but started to feel some strain. Now, I
need to jump through an inheritance chain just to see what my Joiner is
really doing. It wasn't so bad, but I did start to feel a little uneasy.
Bad memories.

So, the solution to a problem like this is to create a Joiner factory.
Which is essentially what I started to write before I started remembering
how Collectors and Gatherers worked. At that point, I kind of realized that
this is worth suggesting, which prompted me to write my original email.

Like I said, not a big deal if you don't give it to me -- I can just make
my own.

But yes, that is the surrounding context behind that quote. Let me know if
you need more details.


On Fri, Aug 15, 2025, 9:25 AM Viktor Klang <viktor.klang at oracle.com> wrote:

> Hi David,
>
> First of all—thank you for your feedback!
>
> I'm curious to learn more about why you ended up in the situation you
> describe below, specifically about what use-cases led you into wishing for
> an augmentation to Joiner to facilitate composition.
>
> Are you able to share more details?
>
> >Which, funnily enough, led to a slightly different problem -- I found
> myself wanting an easier way to create Joiners. Since I was leaning on
> Joiners so much more heavily than I was for STS, I ended up creating many
> Joiners that do almost the same thing, with just minor variations. And
> inheritance wasn't always the right answer, as I can't inherit from
> multiple classes. Plus, most of my joiners were stateful, but I only wanted
> the non-stateful parts of it. I could do composition, but it sort of felt
> weird to delegate to multiple other Joiners.
>
> Cheers,
>>
>
> *Viktor Klang*
> Software Architect, Java Platform Group
> Oracle
> ------------------------------
> *From:* loom-dev <loom-dev-retn at openjdk.org> on behalf of David Alayachew
> <davidalayachew at gmail.com>
> *Sent:* Friday, 15 August 2025 11:52
> *To:* loom-dev <loom-dev at openjdk.org>
> *Subject:* My experience with Structured Concurrency
>
> Hello @loom-dev <loom-dev at openjdk.org>,
>
> I just wanted to share my experience with Structured Concurrency. I had
> actually been using it for a while now, but only recently got experience
> with the new Joiner. After trying it out, my previously stated opinion has
> changed.
>
> Overall, Structured Concurrency has been a pleasure. I'll avoid repeating
> ALL my old thoughts and just highlight the KEY details.
>
> * Structured Concurrency is excellent for complex error-handling.
> Receiving exceptions via the subtask makes all the error-handling less
> painful.
> * Structured Concurrency makes nesting scopes a breeze, a task I
> historically found very painful to do.
> * Inheritance allows me to take an existing Scope (now Joiner), and modify
> only what I need to in order to modify it for my use case. Great for
> reusing old strategies in new ways.
>
> Now for the new stuff -- having Joiner be the point of extension
> definitely proved to be the right move imo. I didn't mention this in my
> original message, but while it was easy to get a scope set up using
> inheritance, it wasn't always clear what invariants needed to be
> maintained. For example, the ensureOwnerAndJoined method. Was that
> something we needed to call when inheriting? On which methods? Just join()?
>
> The Joiner solution is comparatively simpler, which actually meant that I
> ended up creating way more Joiners, rather than only several STS'. Joiners
> invariants are obvious, and there is no ambiguity on what is expected from
> the implementor.
>
> Which, funnily enough, led to a slightly different problem -- I found
> myself wanting an easier way to create Joiners. Since I was leaning on
> Joiners so much more heavily than I was for STS, I ended up creating many
> Joiners that do almost the same thing, with just minor variations. And
> inheritance wasn't always the right answer, as I can't inherit from
> multiple classes. Plus, most of my joiners were stateful, but I only wanted
> the non-stateful parts of it. I could do composition, but it sort of felt
> weird to delegate to multiple other Joiners.
>
> Part of me kept wondering how well a factory method, similar to the ones
> for Collectors and Gatherers, might fare for Joiners.
>
> Regardless, even if we don't get that factory method, this library has
> been a pleasure, and I can't wait to properly implement this once it goes
> live.
>
> Thank you for your time and consideration.
> David Alayachew
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/loom-dev/attachments/20250815/7ebd9984/attachment-0001.htm>


More information about the loom-dev mailing list