Header menu logo IcedTasks

How to use CancellableTask in a console app

See Console App docs

To use a cancellableTask with a console app, we'll need to create a CancellationTokenSource and pass the CancellationToken to the cancellableTask.

In this example, we'll tie the CancellationTokenSource to the console app's cancellation token so that when the user presses Ctrl+C, the cancellableTask will be cancelled.

#r "nuget: IcedTasks"

open IcedTasks

/// Set of Task based helpers
module Task =
    open System.Threading
    open System.Threading.Tasks

    /// <summary>Queues the specified work to run on the thread pool. Helper for Task.Run</summary>
    let runOnThreadpool (cancellationToken: CancellationToken) (func: unit -> Task<'b>) =
        Task.Run<'b>(func, cancellationToken)

    /// <summary>Helper for t.GetAwaiter().GetResult()</summary>
    let runSynchounously (t: Task<'b>) = t.GetAwaiter().GetResult()

module MainTask =
    open System
    open System.Threading
    open System.Threading.Tasks

    // This is a helper to cancel the CancellationTokenSource if it hasn't already been cancelled or disposed.
    let inline tryCancel (cts: CancellationTokenSource) =
        try
            cts.Cancel()
        with :? ObjectDisposedException ->
            // if CTS is disposed we're probably exiting cleanly
            ()

    // This will set up the cancellation token source to be cancelled when the user presses Ctrl+C or when the app is unloaded
    let setupCloseSignalers (cts: CancellationTokenSource) =
        Console.CancelKeyPress.Add(fun _ ->
            printfn "CancelKeyPress"
            tryCancel cts
        )

        System.Runtime.Loader.AssemblyLoadContext.Default.add_Unloading (fun _ ->
            printfn "AssemblyLoadContext unload"
            tryCancel cts
        )

        AppDomain.CurrentDomain.ProcessExit.Add(fun _ ->
            printfn "ProcessExit"
            tryCancel cts
        )

    let mainAsync (argv: string array) =
        cancellableTask {
            let! ctoken = CancellableTask.getCancellationToken ()
            printfn "Doing work!"
            do! Task.Delay(1000, ctoken)
            printfn "Work done"
            return 0
        }

    [<EntryPoint>]
    let main argv =
        use cts = new CancellationTokenSource()
        //
        setupCloseSignalers cts

        Task.runOnThreadpool cts.Token (fun () -> (mainAsync argv cts.Token))
        // This will block until the cancellableTask is done or cancelled
        // This should only be called once at the start of your app
        |> Task.runSynchounously
namespace IcedTasks
namespace System
namespace System.Threading
namespace System.Threading.Tasks
val runOnThreadpool: cancellationToken: CancellationToken -> func: (unit -> Task<'b>) -> Task<'b>
 <summary>Queues the specified work to run on the thread pool. Helper for Task.Run</summary>
val cancellationToken: CancellationToken
Multiple items
[<Struct>] type CancellationToken = new: canceled: bool -> unit member Equals: other: obj -> bool + 1 overload member GetHashCode: unit -> int member Register: callback: Action -> CancellationTokenRegistration + 4 overloads member ThrowIfCancellationRequested: unit -> unit member UnsafeRegister: callback: Action<obj,CancellationToken> * state: obj -> CancellationTokenRegistration + 1 overload static member (<>) : left: CancellationToken * right: CancellationToken -> bool static member (=) : left: CancellationToken * right: CancellationToken -> bool member CanBeCanceled: bool member IsCancellationRequested: bool ...
<summary>Propagates notification that operations should be canceled.</summary>

--------------------
CancellationToken ()
CancellationToken(canceled: bool) : CancellationToken
val func: (unit -> Task<'b>)
type unit = Unit
Multiple items
type Task = interface IAsyncResult interface IDisposable new: action: Action -> unit + 7 overloads member ConfigureAwait: continueOnCapturedContext: bool -> ConfiguredTaskAwaitable + 1 overload member ContinueWith: continuationAction: Action<Task,obj> * state: obj -> Task + 19 overloads member Dispose: unit -> unit member GetAwaiter: unit -> TaskAwaiter member RunSynchronously: unit -> unit + 1 overload member Start: unit -> unit + 1 overload member Wait: unit -> unit + 5 overloads ...
<summary>Represents an asynchronous operation.</summary>

--------------------
type Task<'TResult> = inherit Task new: ``function`` : Func<obj,'TResult> * state: obj -> unit + 7 overloads member ConfigureAwait: continueOnCapturedContext: bool -> ConfiguredTaskAwaitable<'TResult> + 1 overload member ContinueWith: continuationAction: Action<Task<'TResult>,obj> * state: obj -> Task + 19 overloads member GetAwaiter: unit -> TaskAwaiter<'TResult> member WaitAsync: cancellationToken: CancellationToken -> Task<'TResult> + 4 overloads member Result: 'TResult static member Factory: TaskFactory<'TResult>
<summary>Represents an asynchronous operation that can return a value.</summary>
<typeparam name="TResult">The type of the result produced by this <see cref="T:System.Threading.Tasks.Task`1" />.</typeparam>


--------------------
Task(action: System.Action) : Task
Task(action: System.Action, cancellationToken: CancellationToken) : Task
Task(action: System.Action, creationOptions: TaskCreationOptions) : Task
Task(action: System.Action<obj>, state: obj) : Task
Task(action: System.Action, cancellationToken: CancellationToken, creationOptions: TaskCreationOptions) : Task
Task(action: System.Action<obj>, state: obj, cancellationToken: CancellationToken) : Task
Task(action: System.Action<obj>, state: obj, creationOptions: TaskCreationOptions) : Task
Task(action: System.Action<obj>, state: obj, cancellationToken: CancellationToken, creationOptions: TaskCreationOptions) : Task

--------------------
Task(``function`` : System.Func<'TResult>) : Task<'TResult>
Task(``function`` : System.Func<obj,'TResult>, state: obj) : Task<'TResult>
Task(``function`` : System.Func<'TResult>, cancellationToken: CancellationToken) : Task<'TResult>
Task(``function`` : System.Func<'TResult>, creationOptions: TaskCreationOptions) : Task<'TResult>
Task(``function`` : System.Func<obj,'TResult>, state: obj, cancellationToken: CancellationToken) : Task<'TResult>
Task(``function`` : System.Func<obj,'TResult>, state: obj, creationOptions: TaskCreationOptions) : Task<'TResult>
Task(``function`` : System.Func<'TResult>, cancellationToken: CancellationToken, creationOptions: TaskCreationOptions) : Task<'TResult>
Task(``function`` : System.Func<obj,'TResult>, state: obj, cancellationToken: CancellationToken, creationOptions: TaskCreationOptions) : Task<'TResult>
'b
Task.Run<'TResult>(``function`` : System.Func<'TResult>) : Task<'TResult>
Task.Run<'TResult>(``function`` : System.Func<Task<'TResult>>) : Task<'TResult>
Task.Run(``function`` : System.Func<Task>) : Task
Task.Run(action: System.Action) : Task
Task.Run<'TResult>(``function`` : System.Func<'TResult>, cancellationToken: CancellationToken) : Task<'TResult>
Task.Run<'TResult>(``function`` : System.Func<Task<'TResult>>, cancellationToken: CancellationToken) : Task<'TResult>
Task.Run(``function`` : System.Func<Task>, cancellationToken: CancellationToken) : Task
Task.Run(action: System.Action, cancellationToken: CancellationToken) : Task
val runSynchounously: t: Task<'b> -> 'b
 <summary>Helper for t.GetAwaiter().GetResult()</summary>
val t: Task<'b>
Task.GetAwaiter() : System.Runtime.CompilerServices.TaskAwaiter<'b>
module MainTask from Cancellable-Task-In-Console-App
val tryCancel: cts: CancellationTokenSource -> unit
val cts: CancellationTokenSource
Multiple items
type CancellationTokenSource = interface IDisposable new: unit -> unit + 3 overloads member Cancel: unit -> unit + 1 overload member CancelAfter: millisecondsDelay: int -> unit + 1 overload member CancelAsync: unit -> Task member Dispose: unit -> unit member TryReset: unit -> bool static member CreateLinkedTokenSource: token: CancellationToken -> CancellationTokenSource + 3 overloads member IsCancellationRequested: bool member Token: CancellationToken
<summary>Signals to a <see cref="T:System.Threading.CancellationToken" /> that it should be canceled.</summary>

--------------------
CancellationTokenSource() : CancellationTokenSource
CancellationTokenSource(millisecondsDelay: int) : CancellationTokenSource
CancellationTokenSource(delay: TimeSpan) : CancellationTokenSource
CancellationTokenSource(delay: TimeSpan, timeProvider: TimeProvider) : CancellationTokenSource
CancellationTokenSource.Cancel() : unit
CancellationTokenSource.Cancel(throwOnFirstException: bool) : unit
Multiple items
type ObjectDisposedException = inherit InvalidOperationException new: objectName: string -> unit + 2 overloads member GetObjectData: info: SerializationInfo * context: StreamingContext -> unit static member ThrowIf: condition: bool * instance: obj -> unit + 1 overload member Message: string member ObjectName: string
<summary>The exception that is thrown when an operation is performed on a disposed object.</summary>

--------------------
ObjectDisposedException(objectName: string) : ObjectDisposedException
ObjectDisposedException(message: string, innerException: exn) : ObjectDisposedException
ObjectDisposedException(objectName: string, message: string) : ObjectDisposedException
val setupCloseSignalers: cts: CancellationTokenSource -> unit
type Console = static member Beep: unit -> unit + 1 overload static member Clear: unit -> unit static member GetCursorPosition: unit -> struct (int * int) static member MoveBufferArea: sourceLeft: int * sourceTop: int * sourceWidth: int * sourceHeight: int * targetLeft: int * targetTop: int -> unit + 1 overload static member OpenStandardError: unit -> Stream + 1 overload static member OpenStandardInput: unit -> Stream + 1 overload static member OpenStandardOutput: unit -> Stream + 1 overload static member Read: unit -> int static member ReadKey: unit -> ConsoleKeyInfo + 1 overload static member ReadLine: unit -> string ...
<summary>Represents the standard input, output, and error streams for console applications. This class cannot be inherited.</summary>
event Console.CancelKeyPress: IEvent<ConsoleCancelEventHandler,ConsoleCancelEventArgs>
<summary>Occurs when the <see cref="F:System.ConsoleModifiers.Control" /> modifier key (Ctrl) and either the <see cref="F:System.ConsoleKey.C" /> console key (C) or the Break key are pressed simultaneously (Ctrl+C or Ctrl+Break).</summary>
member IObservable.Add: callback: ('T -> unit) -> unit
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
namespace System.Runtime
namespace System.Runtime.Loader
Multiple items
type AssemblyLoadContext = new: name: string * ?isCollectible: bool -> unit member EnterContextualReflection: unit -> ContextualReflectionScope + 1 overload member LoadFromAssemblyName: assemblyName: AssemblyName -> Assembly member LoadFromAssemblyPath: assemblyPath: string -> Assembly member LoadFromNativeImagePath: nativeImagePath: string * assemblyPath: string -> Assembly member LoadFromStream: assembly: Stream -> Assembly + 1 overload member SetProfileOptimizationRoot: directoryPath: string -> unit member StartProfileOptimization: profile: string -> unit member ToString: unit -> string member Unload: unit -> unit ...
<summary>Represents the runtime's concept of a scope for assembly loading.</summary>

--------------------
Runtime.Loader.AssemblyLoadContext(name: string, ?isCollectible: bool) : Runtime.Loader.AssemblyLoadContext
property Runtime.Loader.AssemblyLoadContext.Default: Runtime.Loader.AssemblyLoadContext with get
<summary>Gets the default <see cref="T:System.Runtime.Loader.AssemblyLoadContext" />. The default context contains the main application assembly and its static dependencies.</summary>
<returns>The default assembly load context.</returns>
Runtime.Loader.AssemblyLoadContext.add_Unloading(value: Action<Runtime.Loader.AssemblyLoadContext>) : unit
type AppDomain = inherit MarshalByRefObject member AppendPrivatePath: path: string -> unit member ApplyPolicy: assemblyName: string -> string member ClearPrivatePath: unit -> unit member ClearShadowCopyPath: unit -> unit member CreateInstance: assemblyName: string * typeName: string -> ObjectHandle + 2 overloads member CreateInstanceAndUnwrap: assemblyName: string * typeName: string -> obj + 2 overloads member CreateInstanceFrom: assemblyFile: string * typeName: string -> ObjectHandle + 2 overloads member CreateInstanceFromAndUnwrap: assemblyFile: string * typeName: string -> obj + 2 overloads member ExecuteAssembly: assemblyFile: string -> int + 2 overloads ...
<summary>Represents an application domain, which is an isolated environment where applications execute. This class cannot be inherited.</summary>
property AppDomain.CurrentDomain: AppDomain with get
<summary>Gets the current application domain for the current <see cref="T:System.Threading.Thread" />.</summary>
<returns>The current application domain.</returns>
event AppDomain.ProcessExit: IEvent<EventHandler,EventArgs>
<summary>Occurs when the default application domain's parent process exits.</summary>
val mainAsync: argv: string array -> CancellableTask<int>
val argv: string array
Multiple items
val string: value: 'T -> string

--------------------
type string = String
type 'T array = 'T array
val cancellableTask: CancellableTaskBuilder
<summary> Builds a cancellableTask using computation expression syntax. </summary>
val ctoken: CancellationToken
Multiple items
module CancellableTask from IcedTasks.CancellableTasks

--------------------
type CancellableTask = CancellationToken -> Task
<summary> CancellationToken -&gt; Task </summary>

--------------------
type CancellableTask<'T> = CancellationToken -> Task<'T>
<summary> CancellationToken -&gt; Task&lt;'T&gt; </summary>
val getCancellationToken: unit -> ct: CancellationToken -> ValueTask<CancellationToken>
<summary>Gets the default cancellation token for executing computations.</summary>
<returns>The default CancellationToken.</returns>
<category index="3">Cancellation and Exceptions</category>
<example id="default-cancellation-token-1"><code lang="F#"> use tokenSource = new CancellationTokenSource() let primes = [ 2; 3; 5; 7; 11 ] for i in primes do let computation = cancellableTask { let! cancellationToken = CancellableTask.getCancellationToken() do! Task.Delay(i * 1000, cancellationToken) printfn $"{i}" } computation tokenSource.Token |&gt; ignore Thread.Sleep(6000) tokenSource.Cancel() printfn "Tasks Finished" </code> This will print "2" 2 seconds from start, "3" 3 seconds from start, "5" 5 seconds from start, cease computation and then followed by "Tasks Finished". </example>
Multiple items
type Task = interface IAsyncResult interface IDisposable new: action: Action -> unit + 7 overloads member ConfigureAwait: continueOnCapturedContext: bool -> ConfiguredTaskAwaitable + 1 overload member ContinueWith: continuationAction: Action<Task,obj> * state: obj -> Task + 19 overloads member Dispose: unit -> unit member GetAwaiter: unit -> TaskAwaiter member RunSynchronously: unit -> unit + 1 overload member Start: unit -> unit + 1 overload member Wait: unit -> unit + 5 overloads ...
<summary>Represents an asynchronous operation.</summary>

--------------------
type Task<'TResult> = inherit Task new: ``function`` : Func<obj,'TResult> * state: obj -> unit + 7 overloads member ConfigureAwait: continueOnCapturedContext: bool -> ConfiguredTaskAwaitable<'TResult> + 1 overload member ContinueWith: continuationAction: Action<Task<'TResult>,obj> * state: obj -> Task + 19 overloads member GetAwaiter: unit -> TaskAwaiter<'TResult> member WaitAsync: cancellationToken: CancellationToken -> Task<'TResult> + 4 overloads member Result: 'TResult static member Factory: TaskFactory<'TResult>
<summary>Represents an asynchronous operation that can return a value.</summary>
<typeparam name="TResult">The type of the result produced by this <see cref="T:System.Threading.Tasks.Task`1" />.</typeparam>


--------------------
Task(action: Action) : Task
Task(action: Action, cancellationToken: CancellationToken) : Task
Task(action: Action, creationOptions: TaskCreationOptions) : Task
Task(action: Action<obj>, state: obj) : Task
Task(action: Action, cancellationToken: CancellationToken, creationOptions: TaskCreationOptions) : Task
Task(action: Action<obj>, state: obj, cancellationToken: CancellationToken) : Task
Task(action: Action<obj>, state: obj, creationOptions: TaskCreationOptions) : Task
Task(action: Action<obj>, state: obj, cancellationToken: CancellationToken, creationOptions: TaskCreationOptions) : Task

--------------------
Task(``function`` : Func<'TResult>) : Task<'TResult>
Task(``function`` : Func<obj,'TResult>, state: obj) : Task<'TResult>
Task(``function`` : Func<'TResult>, cancellationToken: CancellationToken) : Task<'TResult>
Task(``function`` : Func<'TResult>, creationOptions: TaskCreationOptions) : Task<'TResult>
Task(``function`` : Func<obj,'TResult>, state: obj, cancellationToken: CancellationToken) : Task<'TResult>
Task(``function`` : Func<obj,'TResult>, state: obj, creationOptions: TaskCreationOptions) : Task<'TResult>
Task(``function`` : Func<'TResult>, cancellationToken: CancellationToken, creationOptions: TaskCreationOptions) : Task<'TResult>
Task(``function`` : Func<obj,'TResult>, state: obj, cancellationToken: CancellationToken, creationOptions: TaskCreationOptions) : Task<'TResult>
Task.Delay(delay: TimeSpan) : Task
Task.Delay(millisecondsDelay: int) : Task
Task.Delay(delay: TimeSpan, timeProvider: TimeProvider) : Task
Task.Delay(delay: TimeSpan, cancellationToken: CancellationToken) : Task
Task.Delay(millisecondsDelay: int, cancellationToken: CancellationToken) : Task
Task.Delay(delay: TimeSpan, timeProvider: TimeProvider, cancellationToken: CancellationToken) : Task
Multiple items
type EntryPointAttribute = inherit Attribute new: unit -> EntryPointAttribute

--------------------
new: unit -> EntryPointAttribute
val main: argv: string array -> int
property CancellationTokenSource.Token: CancellationToken with get
<summary>Gets the <see cref="T:System.Threading.CancellationToken" /> associated with this <see cref="T:System.Threading.CancellationTokenSource" />.</summary>
<exception cref="T:System.ObjectDisposedException">The token source has been disposed.</exception>
<returns>The <see cref="T:System.Threading.CancellationToken" /> associated with this <see cref="T:System.Threading.CancellationTokenSource" />.</returns>

Type something to start searching.