Orleans.FSharp Analyzers
Compile-time F# analyzer: OF0001 warns on async usage with AllowAsync opt-out.
Orleans.FSharp Analyzers
Section titled “Orleans.FSharp Analyzers”Compile-time feedback for idiomatic Orleans grain code.
Installation
Section titled “Installation”dotnet add package Orleans.FSharp.AnalyzersNote: F# analyzers surface warnings in editors that support Ionide (VS Code + Ionide extension, JetBrains Rider). They also run via the
fsharp-analyzersCLI tool.
OF0001 — Use task { } instead of async { }
Section titled “OF0001 — Use task { } instead of async { }”Description
Section titled “Description”async { } computation expressions are banned in Orleans.FSharp grain code. Orleans is built on .NET Task-based concurrency. Using async { } requires an unnecessary Async.AwaitTask / Async.StartAsTask conversion at every grain boundary, adds overhead, and is incompatible with Orleans’s CancellationToken propagation model.
Use task { } (from IcedTasks or .NET 6+) instead. It compiles directly to a Task<'T> and is fully compatible with Orleans grain handlers.
Example (warning)
Section titled “Example (warning)”// ⚠️ OF0001: Use task { } instead of async { }let handler state cmd = async { // <-- warning here match cmd with | Increment -> return { Count = state.Count + 1 }, box (state.Count + 1) | GetValue -> return state, box state.Count }// ✅ Correctlet handler state cmd = task { match cmd with | Increment -> return { Count = state.Count + 1 }, box (state.Count + 1) | GetValue -> return state, box state.Count }Suppression with [<AllowAsync>]
Section titled “Suppression with [<AllowAsync>]”When async { } is genuinely required — for example, interoperating with a library that returns Async<'T> — suppress OF0001 on the specific binding:
open Orleans.FSharp.Analyzers.AsyncUsageAnalyzer
[<AllowAsync>]let fetchFromLegacyApi (url: string) : Async<string> = async { let! result = legacyHttpClient.GetAsync(url) |> Async.AwaitTask return! result.Content.ReadAsStringAsync() |> Async.AwaitTask }[<AllowAsync>] suppresses the warning only for the annotated binding. Other async { } usages in the same module are still flagged.
When async { } is acceptable
Section titled “When async { } is acceptable”- Interop adapters that bridge
Async<'T>APIs toTask<'T>callers (use[<AllowAsync>]) - Script files (
.fsx) that use the F#Asyncworkflow (use[<AllowAsync>]) - Unit tests calling
Async.RunSynchronously(use[<AllowAsync>]on the test helper)
In all other cases, use task { }.
Running analyzers from the CLI
Section titled “Running analyzers from the CLI”Install the analyzer CLI tool:
dotnet tool install --global fsharp-analyzersRun against your project:
fsharp-analyzers --project MyGrains.fsproj --analyzers-path <path-to-Orleans.FSharp.Analyzers.dll>Analyzer list
Section titled “Analyzer list”| Code | Severity | Description |
|---|---|---|
| OF0001 | Warning | async { } should be task { } |
See also
Section titled “See also”- Getting Started — quick introduction to Orleans.FSharp
- Grain Definition — complete
grain { }CE reference - Advanced — transactions, telemetry, shutdown, migration