Use with F# and Visual Basic
Asynchronous methods in the Polly.Core API return either ValueTask
or ValueTask<T>
instead of Task
or Task<T>
. This is because Polly v8 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 Polly
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 Polly 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 Polly 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 Polly
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 Polly 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 Polly 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