Use with F# and Visual Basic
Asynchronous methods in the Paramore.Fences.Core API return either ValueTask or ValueTask<T>
instead of Task or Task<T>. This is because the v8 API was designed to be optimized
for high performance and uses ValueTask to avoid unnecessary allocations.
One downside to this choice is that in Visual Basic and F#, it is not possible to directly
await a method that returns ValueTask or ValueTask<T>, instead requiring the use of
Task and Task<T>.
A proposal to support awaiting ValueTask can be found in F# language design repository:
[RFC FS-1021 Discussion] Support Interop with ValueTask in Async Type.
To work around this limitation, you can use the AsTask() method to convert a
ValueTask to a Task in F# and Visual Basic. This does however introduce an allocation and make
the code a bit more difficult to work with compared to C#.
Examples of such conversions are shown below.
F#
open FSharp.Control
open System
open System.Threading
open System.Threading.Tasks
open IcedTasks
open Paramore.Fences
let getBestFilmAsync token =
task {
do! Task.Delay(1000, token)
return "https://www.imdb.com/title/tt0080684/"
}
let demo () =
task {
// The ResiliencePipelineBuilder creates a ResiliencePipeline
// that can be executed synchronously or asynchronously
// and for both void and result-returning user-callbacks.
let pipeline =
ResiliencePipelineBuilder()
.AddTimeout(TimeSpan.FromSeconds(5))
.Build()
let token = CancellationToken.None
// Synchronously
pipeline.Execute(fun () -> printfn "Hello, world!")
// Asynchronously
// Note that Fences expects a ValueTask to be returned, so the function uses the valueTask builder
// from IcedTasks to make it easier to use ValueTask. See https://github.com/TheAngryByrd/IcedTasks.
do! pipeline.ExecuteAsync(
fun token ->
valueTask {
printfn "Hello, world! Waiting for 2 seconds..."
do! Task.Delay(1000, token)
printfn "Wait complete."
}
, token
)
// Synchronously with result
let someResult = pipeline.Execute(fun token -> "some-result")
// Asynchronously with result
// Note that Fences expects a ValueTask<T> to be returned, so the function uses the valueTask builder
// from IcedTasks to make it easier to use ValueTask<T>. See https://github.com/TheAngryByrd/IcedTasks.
let! bestFilm = pipeline.ExecuteAsync(
fun token ->
valueTask {
let! url = getBestFilmAsync(token)
return url
}
, token
)
printfn $"Link to the best film: {bestFilm}"
}
Visual Basic
Imports System.Threading
Imports Paramore.Fences
Module Program
Sub Main()
Demo().Wait()
End Sub
Async Function Demo() As Task
' The ResiliencePipelineBuilder creates a ResiliencePipeline
' that can be executed synchronously or asynchronously
' and for both void and result-returning user-callbacks.
Dim pipeline = New ResiliencePipelineBuilder().AddTimeout(TimeSpan.FromSeconds(5)).Build()
' Synchronously
pipeline.Execute(Sub()
Console.WriteLine("Hello, world!")
End Sub)
' Asynchronously
' Note that the function is wrapped in a ValueTask for Fences to use as VB.NET cannot
' await ValueTask directly, and AsTask() is used to convert the ValueTask returned by
' ExecuteAsync() to a Task so it can be awaited.
Await pipeline.ExecuteAsync(Function(token)
Return New ValueTask(GreetAndWaitAsync(token))
End Function,
CancellationToken.None).AsTask()
' Synchronously with result
Dim someResult = pipeline.Execute(Function(token)
Return "some-result"
End Function)
' Asynchronously with result
' Note that the function is wrapped in a ValueTask(Of String) for Fences to use as VB.NET cannot
' await ValueTask directly, and AsTask() is used to convert the ValueTask(Of String) returned by
' ExecuteAsync() to a Task(Of String) so it can be awaited.
Dim bestFilm = Await pipeline.ExecuteAsync(Function(token)
Return New ValueTask(Of String)(GetBestFilmAsync(token))
End Function,
CancellationToken.None).AsTask()
Console.WriteLine("Link to the best film: {0}", bestFilm)
End Function
Async Function GreetAndWaitAsync(token As CancellationToken) As Task
Console.WriteLine("Hello, world! Waiting for 1 second...")
Await Task.Delay(1000, token)
End Function
Async Function GetBestFilmAsync(token As CancellationToken) As Task(Of String)
Await Task.Delay(1000, token)
Return "https://www.imdb.com/title/tt0080684/"
End Function
End Module