Skip to content

v0.9.2

Choose a tag to compare

@github-actions github-actions released this 14 Sep 02:50
· 24 commits to main since this release

Axial 0.9.2

Fix

Flows are now stack safe when their steps complete synchronously. Each bind, map, loop iteration, traversal
element, stream pull, and schedule recurrence previously nested further into the stack, so long chains
overflowed it and terminated the process. On a 1MB thread stack (the Windows default) that took only a few
thousand steps: a flow { for ... } over a large sequence of cached or already-known values was enough.

Affected shapes, all covered by tests/Axial.Tests/StackSafetyTests.fs on a 1MB-stack thread:

  • for and while loops in flow { }
  • Flow.traverse and Flow.sequence
  • long left-nested Flow.bind, Flow.map, and Flow.orElse chains
  • recursive flows deferred with Flow.delay or the flow { } builder
  • FlowStream pipelines (for example filter skipping long runs) and Schedule.repeat/Schedule.retry

Flow invocation and synchronous fold continuations now count nesting depth per thread; past a fixed depth,
execution continues on a fresh thread-pool stack via Task.Run, which preserves AsyncLocal runtime state and
cannot deadlock a caller that blocks under a SynchronizationContext. Already-completed executions also skip
the task state machine, so each step costs fewer frames. Fable's Async already trampolines and is unchanged.

Flow values built by eager F# recursion (let rec f n = f (n - 1) |> Flow.map g) still recurse in F# before
Axial runs; defer the recursive call with Flow.delay.