Skip to content

TaskEx: AwaitTaskCorrect / Task.toAsync / Async.ofTask #141

Open

Description

@bartelink

Replaces #129. TaskEx top level issue: #139

The default implementation of the Async.AwaitTask methods in FSharp.Core have some key shortcomings:

  1. when the Task faults, yielding an exception, that exception is typically (always?) wrapped in an egregious AggregateException
  2. the default implementation does not abort/cancel when the ambient CancellationToken of the async expr within which Async.AwaitTask is triggered
  3. cancelling an Async computation should not just abort the processing, it should also propagate a TaskCancelledException to align with the behavior of Task

While it can be argued that the current behavior is 'wrong', it's also obvious that breaking it would be untenable, and the semantic differences are beyond what one might cover with subtle overloads and/or adding optional arguments etc.

Current proposed APIs (will be updated inline based on any discussion below):

module Async =
    let inline ofTask (t : Task<'t>) : Async<'t> = AwaitTaskCorrect t
    let inline ofUnitTask (t : Task) : Async<'t> = AwaitTaskCorrect t
module Task =
    let inline toAsync (t : Task<'t>) : Async<'t> = Async.ofTask t

NOTES:

  • the above naming is taken from the helpers within TaskSeq, which are exposed in the FSharp.Control namespace. NOTE the current implementations use Async.AwaitTask, but that was not as a conscious choice, and there is a desire` to fix at least some of the shortcomings noted
  • given the fact that task and async are now first class citizens of FSharp.Core, having an of/to pairing would seem to make sense. This is open to debate; not sure the degree to which the prior art is consistent wrt this beyond collection types/modules
  • There is an fslang-suggestion regarding this. The purpose of this issue is as a placeholder for potentially filling the gap until this issue can be more thoroughly resolved in FSharp.Core proper.
  • Equinox, Propulsion and FSharp.AWS.DynamoDB all have copies of the canonical impl in Eirik's fssnip. Not ruling out tweaks to the semantics, but ideally those libraries, and others, would all share the same semantics
  • if this is handled as a module, one also frequently needs an ofUnitTask alongside as above (Async.AwaitTask is a pair of overloaded methods, which often brings its own issues with intellisense and error messages etc)

Activity

  1. changed the title [-]TaskShims: AwaitTaskCorrect / Task.toAsync / Async.ofTask[/-] [+]TaskEx: AwaitTaskCorrect / Task.toAsync / Async.ofTask[/+] on Jan 10, 2023
  2. added
    feature requestNew feature or enhancement request
    topic: task-exRelated to the proposed new TaskEx library, which should get its own oss haven
    on Oct 29, 2023
  3. added this to the vFuture milestone on Mar 18, 2024
  4. github-actions commented on Mar 9, 2026

    @github-actions
  5. bartelink commented on Mar 18, 2026

    @bartelink
    MemberAuthor
  6. github-actions commented on Apr 16, 2026

    @github-actions
    Contributor

    🤖 This is an automated response from Repo Assist.

    Thanks for the update, @bartelink — noted. Keeping this as a placeholder makes sense given the live inconsistency between:

    • The private awaitTaskCorrect in AsyncExtensions.fs, which correctly unwraps single inner exceptions from AggregateException before routing to the error continuation, and
    • The public Async.ofTask / Async.ofUnitTask in Utils.fs, which still delegate to Async.AwaitTask and so don't unwrap AggregateException.

    When there's appetite to fix the public API, the fix is straightforward — lifting a generic version of awaitTaskCorrect from AsyncExtensions.fs into Utils.fs and wiring Async.ofTask/Async.ofUnitTask to it. That would be a technically breaking change for any code that currently catches AggregateException around these, so it warrants a version bump and changelog note.

    Generated by 🌈 Repo Assist, see workflow run.

    Generated by 🌈 Repo Assist, see workflow run. Learn more.

    To install this agentic workflow, run

    gh aw add githubnext/agentics/workflows/repo-assist.md@97143ac59cb3a13ef2a77581f929f06719c7402a
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature requestNew feature or enhancement requesttopic: task-exRelated to the proposed new TaskEx library, which should get its own oss haven

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions