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 { } instead — the computation expression FSharp.Core has shipped since F# 6 (IcedTasks adds cancellable and resumable variants on top of it). It compiles directly to a Task<'T> and is fully compatible with Orleans grain handlers.
Example (warning)
Section titled “Example (warning)”type CounterState = { count: int }
// ⚠️ OF0001: Use task { } instead of async { }let handler (state: CounterState) () = async { // warning here let next = { count = state.count + 1 } return next, next.count }type CounterState = { count: int }
// ✅ Correctlet handler (state: CounterState) () = task { let next = { count = state.count + 1 } return next, next.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 System.Net.Httpopen Orleans.FSharp.Analyzers.AsyncUsageAnalyzer
[<AllowAsync>]let fetchFromLegacyApi (url: string) : Async<string> = async { use client = new HttpClient() return! client.GetStringAsync(url) |> 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
- Legacy API — maintenance documentation for earlier authoring models
- Advanced — transactions, OpenTelemetry, shutdown, migration