How to use CancellableTask in Falco
To use a cancellableTask with Falco, we'll need to get the RequestAborted property off the HttpContext.
We'll start off with a slightly longer version but then make a helper for this.
// This just the dance to get Falco to compile for this example.
// Really you'd set up these references in an fsproj
#load "../../runtime-scripts/Microsoft.AspNetCore.App-latest-8.fsx"
#r "nuget: Falco"
#r "nuget: IcedTasks"
open Microsoft.AspNetCore.Http
open System.Threading
open System.Threading.Tasks
open IcedTasks
open Falco
open Falco.Routing
// This is a stand in for some real database call like Npgsql where it would take a CancellationToken
type Database =
static member Get(query, queryParams, cancellationToken: CancellationToken) =
task { do! Task.Delay(10) }
module ExampleVerbose =
// Some function that's doing the real handler's work
let myRealWork ctx =
cancellableTask {
// use a lamdbda to get the cancellableTask's current CancellationToken
let! result =
fun ct -> Database.Get("SELECT foo FROM bar where baz = @0", [ "@0", "buzz" ], ct)
return! Response.ofJson result ctx
}
// A helper to get the context's RequestAborted CancellationToken which will give the cancellableTask
// the context to pass long.
let myCustomHandler (ctx: HttpContext) =
task {
let cancellationToken = ctx.RequestAborted
return! myRealWork ctx cancellationToken
}
:> Task
let endpoints = [ get "/" myCustomHandler ]
We'll end up creating our own Routing Handler helpers to make it easier when adding to a webapp.
module RoutingC =
type CancellableHandler = HttpContext -> CancellationToken -> Task<unit>
// A helper to get the context's RequestAborted CancellationToken which will give the cancellableTask
// the context to pass long.
let inline toHandler
(cancellableHandler: HttpContext -> CancellationToken -> Task<unit>)
(ctx: HttpContext)
=
task { return! cancellableHandler ctx ctx.RequestAborted } :> Task
/// HttpEndpoint constructor that matches any HttpVerb.
let any (pattern: string) (handler: CancellableHandler) : HttpEndpoint =
route ANY pattern (toHandler handler)
/// GET HttpEndpoint constructor.
let get (pattern: string) (handler: CancellableHandler) : HttpEndpoint =
route GET pattern (toHandler handler)
/// HEAD HttpEndpoint constructor.
let head (pattern: string) (handler: CancellableHandler) : HttpEndpoint =
route HEAD pattern (toHandler handler)
/// POST HttpEndpoint constructor.
let post (pattern: string) (handler: CancellableHandler) : HttpEndpoint =
route POST pattern (toHandler handler)
/// PUT HttpEndpoint constructor.
let put (pattern: string) (handler: CancellableHandler) : HttpEndpoint =
route PUT pattern (toHandler handler)
/// PATCH HttpEndpoint constructor.
let patch (pattern: string) (handler: CancellableHandler) : HttpEndpoint =
route PATCH pattern (toHandler handler)
/// DELETE HttpEndpoint constructor.
let delete (pattern: string) (handler: CancellableHandler) : HttpEndpoint =
route DELETE pattern (toHandler handler)
/// OPTIONS HttpEndpoint constructor.
let options (pattern: string) (handler: CancellableHandler) : HttpEndpoint =
route OPTIONS pattern (toHandler handler)
/// TRACE HttpEndpoint construct.
let trace (pattern: string) (handler: CancellableHandler) : HttpEndpoint =
route TRACE pattern (toHandler handler)
module ExampleRefactor1 =
// Some function that's doing the real handler's work
let myRealWork ctx =
cancellableTask {
// use a lamdbda to get the cancellableTask's current CancellationToken
let! result =
fun ct -> Database.Get("SELECT foo FROM bar where baz = @0", [ "@0", "buzz" ], ct)
return! Response.ofJson result ctx
}
let endpoints = [ RoutingC.get "/" myRealWork ]
namespace Microsoft
namespace Microsoft.AspNetCore
namespace Microsoft.AspNetCore.Http
namespace System
namespace System.Threading
namespace System.Threading.Tasks
namespace IcedTasks
namespace Falco
module Routing
from Falco
val query: 'a
val queryParams: 'b
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
[<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 task: TaskBuilder
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>
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>
Task.Delay(delay: System.TimeSpan) : Task
Task.Delay(millisecondsDelay: int) : Task
Task.Delay(delay: System.TimeSpan, timeProvider: System.TimeProvider) : Task
Task.Delay(delay: System.TimeSpan, cancellationToken: CancellationToken) : Task
Task.Delay(millisecondsDelay: int, cancellationToken: CancellationToken) : Task
Task.Delay(delay: System.TimeSpan, timeProvider: System.TimeProvider, cancellationToken: CancellationToken) : Task
Task.Delay(millisecondsDelay: int) : Task
Task.Delay(delay: System.TimeSpan, timeProvider: System.TimeProvider) : Task
Task.Delay(delay: System.TimeSpan, cancellationToken: CancellationToken) : Task
Task.Delay(millisecondsDelay: int, cancellationToken: CancellationToken) : Task
Task.Delay(delay: System.TimeSpan, timeProvider: System.TimeProvider, cancellationToken: CancellationToken) : Task
val myRealWork: ctx: HttpContext -> CancellableTask<unit>
val ctx: HttpContext
val cancellableTask: CancellableTaskBuilder
<summary> Builds a cancellableTask using computation expression syntax. </summary>
<summary> Builds a cancellableTask using computation expression syntax. </summary>
val result: unit
val ct: CancellationToken
type Database =
static member Get: query: 'a * queryParams: 'b * cancellationToken: CancellationToken -> Task<unit>
static member Database.Get: query: 'a * queryParams: 'b * cancellationToken: CancellationToken -> Task<unit>
module Response
from Falco
val ofJson: obj: 'T -> HttpHandler
<summary> Returns a "application/json; charset=utf-8" response with the serialized object provided to the client. </summary>
<summary> Returns a "application/json; charset=utf-8" response with the serialized object provided to the client. </summary>
val myCustomHandler: ctx: HttpContext -> Task
type HttpContext =
override Abort: unit -> unit
member Connection: ConnectionInfo
member Features: IFeatureCollection
member Items: IDictionary<obj,obj>
member Request: HttpRequest
member RequestAborted: CancellationToken
member RequestServices: IServiceProvider
member Response: HttpResponse
member Session: ISession
member TraceIdentifier: string
...
property HttpContext.RequestAborted: CancellationToken with get, set
val endpoints: HttpEndpoint list
val get: pattern: string -> handler: HttpHandler -> HttpEndpoint
<summary> GET HttpEndpoint constructor. </summary>
<summary> GET HttpEndpoint constructor. </summary>
type CancellableHandler = HttpContext -> CancellationToken -> Task<unit>
type unit = Unit
val toHandler: cancellableHandler: (HttpContext -> CancellationToken -> Task<unit>) -> ctx: HttpContext -> Task
val cancellableHandler: (HttpContext -> CancellationToken -> Task<unit>)
val any: pattern: string -> handler: CancellableHandler -> HttpEndpoint
HttpEndpoint constructor that matches any HttpVerb.
HttpEndpoint constructor that matches any HttpVerb.
val pattern: string
Multiple items
val string: value: 'T -> string
--------------------
type string = System.String
val string: value: 'T -> string
--------------------
type string = System.String
val handler: CancellableHandler
type HttpEndpoint =
{
Pattern: string
Handlers: (HttpVerb * HttpHandler) seq
Configure: (EndpointBuilder -> EndpointBuilder)
}
<summary> Specifies an association of a route pattern to a collection of HttpEndpointHandler. </summary>
<summary> Specifies an association of a route pattern to a collection of HttpEndpointHandler. </summary>
val route: verb: HttpVerb -> pattern: string -> handler: HttpHandler -> HttpEndpoint
<summary> Constructor for a singular HttpEndpoint. </summary>
<summary> Constructor for a singular HttpEndpoint. </summary>
union case HttpVerb.ANY: HttpVerb
val get: pattern: string -> handler: CancellableHandler -> HttpEndpoint
GET HttpEndpoint constructor.
GET HttpEndpoint constructor.
union case HttpVerb.GET: HttpVerb
val head: pattern: string -> handler: CancellableHandler -> HttpEndpoint
HEAD HttpEndpoint constructor.
HEAD HttpEndpoint constructor.
union case HttpVerb.HEAD: HttpVerb
val post: pattern: string -> handler: CancellableHandler -> HttpEndpoint
POST HttpEndpoint constructor.
POST HttpEndpoint constructor.
union case HttpVerb.POST: HttpVerb
val put: pattern: string -> handler: CancellableHandler -> HttpEndpoint
PUT HttpEndpoint constructor.
PUT HttpEndpoint constructor.
union case HttpVerb.PUT: HttpVerb
val patch: pattern: string -> handler: CancellableHandler -> HttpEndpoint
PATCH HttpEndpoint constructor.
PATCH HttpEndpoint constructor.
union case HttpVerb.PATCH: HttpVerb
val delete: pattern: string -> handler: CancellableHandler -> HttpEndpoint
DELETE HttpEndpoint constructor.
DELETE HttpEndpoint constructor.
union case HttpVerb.DELETE: HttpVerb
val options: pattern: string -> handler: CancellableHandler -> HttpEndpoint
OPTIONS HttpEndpoint constructor.
OPTIONS HttpEndpoint constructor.
union case HttpVerb.OPTIONS: HttpVerb
val trace: pattern: string -> handler: CancellableHandler -> HttpEndpoint
TRACE HttpEndpoint construct.
TRACE HttpEndpoint construct.
union case HttpVerb.TRACE: HttpVerb
module ExampleRefactor1
from Cancellable-Task-In-Falco
module RoutingC
from Cancellable-Task-In-Falco
val get: pattern: string -> handler: RoutingC.CancellableHandler -> HttpEndpoint
GET HttpEndpoint constructor.
GET HttpEndpoint constructor.