Skip to content

Result ordering contract silently flips between bounded and unbounded parallel streaming #365

Description

@thomhurst

Found in the pre-4.0 audit (follow-up to #360/#361).

The same fluent call yields different ordering guarantees depending on configuration, and none of it is documented:

  • ResultAsyncEnumerableParallelProcessor.ExecuteAsync bounded (maxConcurrency: n) → source order (worker pool's ProcessResultsAsync yields per-item completion sources in enqueue order).
  • ResultAsyncEnumerableParallelProcessor.ExecuteAsync unbounded → completion order (tasks.ToIAsyncEnumerable).
  • IAsyncProcessor<T>.GetResultsAsyncEnumerable() (enumerable source) → completion order, while GetResultsAsync() on the same processor → source order.

Failure scenario: user tunes ProcessInParallel() to ProcessInParallel(maxConcurrency: 8) for backpressure and their downstream logic silently starts receiving results in a different order (or vice versa).

Proposal (pick one before 4.0 freezes the contract):

  1. Document the current behavior explicitly per method/configuration (cheapest), or
  2. Unify: streaming APIs always yield completion order (matches "results as they become available" semantics) or always source order — either way, one rule.

Note ordering is observable behavior — changing it post-4.0 is a breaking change, which is why this needs a decision now even if the answer is "document it".

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions