Skip to content

AsyncResult eagerness: the readable spelling of a sequence is a silent race #68

Description

@btravers

From a DX review of the constraints this repo holds deliberately.

Not a challenge to errors-as-values — that is the typesafety commitment and it stays. This is about an ergonomic trap inside it.

examples/order-temporal-worker/src/workflows.ts documents the trap in its own code:

"An AsyncResult is eager — building a step IS starting its activity — so every later step is constructed inside the flatMap of the one before it, or the 'sequence' would run as a race."

So the readable spelling — a flat sequence of steps — is a concurrency bug, and the correct spelling is a nesting ladder. fulfillOrder is the worked example: five steps, each constructed inside the previous one's callback, with compensations nested deeper still. It is correct, it is well commented, and it is hard to read and harder to edit — inserting a step means re-indenting everything below it.

Three properties make this worth an issue rather than a style note:

  1. The failure is silent. A flat sequence still type-checks and still returns a Result; it just runs the steps concurrently. Nothing in the gate catches it — this repo's whole thesis is that mistakes should be compile errors, and this one is not.
  2. It scales badly. The saga is five steps. A ten-step one is ten levels of indentation.
  3. It is the shape newcomers will reach for first, because it is the shape every other language's async code has.

Worth investigating in the issue: whether unthrown offers (or could offer) a generator / do-notation form that sequences without nesting; whether a lazy AsyncResult variant is coherent with the rest of the library; whether a sequence/pipeline combinator over thunks covers the common case; or — the cheapest option — whether a lint rule can flag sibling AsyncResult constructions that were meant to be sequential. The last would turn a silent bug into the compile error this repo would normally insist on.

Note this belongs partly upstream in btravstack/unthrown rather than here; the issue is filed here because the trap is felt here and the example that documents it lives here.

Acceptance

  • A decision on whether a non-nesting sequential form exists, is added, or is declined with a reason.
  • If declined: the trap is documented somewhere a reader meets it before writing a saga — the how-to pages and the @btravstack/temporal reference, not only a comment inside one example's workflow file.
  • Ideally, some gate — lint rule or type — that makes the accidental-race spelling fail rather than run.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P0A correctness trap someone will hit — fix before more is built on itenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions