Skip to content

Silo Configuration

Complete siloConfig CE reference.

Complete guide to the siloConfig { } computation expression.

  • How to configure clustering, storage, streaming, and reminders
  • TLS/mTLS for secure silo communication
  • Dashboard, health checks, and startup tasks
  • Grain versioning, collection age, and endpoints
  • Call filters and grain services

The siloConfig { } CE builds a SiloConfig record. Apply it to a host with SiloConfig.applyToHost:

open Orleans.FSharp.Runtime
let config = siloConfig {
useLocalhostClustering
addMemoryStorage "Default"
}
let builder = HostApplicationBuilder()
SiloConfig.applyToHost config builder
let host = builder.Build()
host.Run()

Or apply directly to an ISiloBuilder with SiloConfig.applyToSiloBuilder.


siloConfig { useLocalhostClustering }

Requires Microsoft.Orleans.Clustering.Redis.

let connStr = Environment.GetEnvironmentVariable("REDIS_CONNECTION")
siloConfig {
addRedisClustering connStr
addMemoryStorage "Default"
}

Requires Microsoft.Orleans.Clustering.AzureStorage.

let connStr = Environment.GetEnvironmentVariable("AZURE_STORAGE_CONNECTION")
siloConfig {
addAzureTableClustering connStr
addMemoryStorage "Default"
}

Requires Microsoft.Orleans.Clustering.AdoNet.

let connStr = Environment.GetEnvironmentVariable("POSTGRES_CONNECTION")
siloConfig {
addAdoNetClustering connStr "Npgsql"
addMemoryStorage "Default"
}

The second argument is the ADO.NET provider invariant. Common values: "Npgsql" (PostgreSQL), "System.Data.SqlClient" (SQL Server), "MySql.Data.MySqlClient" (MySQL).

Use the Kubernetes module for automatic discovery via the Kubernetes API:

open Orleans.FSharp.Kubernetes
siloConfig {
// Use CustomClustering to wire Kubernetes hosting
addCustomStorage "Default" (fun sb -> sb)
}
// Apply Kubernetes clustering separately on the ISiloBuilder
Kubernetes.useKubernetesClustering siloBuilder |> ignore

Requires Microsoft.Orleans.Hosting.Kubernetes.


Data is lost on silo restart. Good for development and testing.

siloConfig { addMemoryStorage "Default" }

Requires Microsoft.Orleans.Persistence.Redis.

let connStr = Environment.GetEnvironmentVariable("REDIS_CONNECTION")
siloConfig { addRedisStorage "Default" connStr }

Requires Microsoft.Orleans.Persistence.AzureStorage.

let connStr = Environment.GetEnvironmentVariable("AZURE_STORAGE_CONNECTION")
siloConfig { addAzureBlobStorage "Default" connStr }

Requires Microsoft.Orleans.Persistence.AzureStorage.

siloConfig { addAzureTableStorage "Default" connStr }

Requires Microsoft.Orleans.Persistence.AdoNet.

siloConfig { addAdoNetStorage "Default" connStr "Npgsql" }

Requires Microsoft.Orleans.Persistence.Cosmos.

let endpoint = Environment.GetEnvironmentVariable("COSMOS_ENDPOINT")
siloConfig { addCosmosStorage "Default" endpoint "MyDatabase" }

Requires Microsoft.Orleans.Persistence.DynamoDB.

siloConfig { addDynamoDbStorage "Default" "us-east-1" }

For any storage provider not covered above:

siloConfig {
addCustomStorage "MyStore" (fun siloBuilder ->
siloBuilder.AddMyCustomStorage("MyStore")
)
}

You can register multiple storage providers with different names:

siloConfig {
useLocalhostClustering
addMemoryStorage "Default"
addRedisStorage "Cache" redisConnStr
addAzureBlobStorage "Archive" azureConnStr
}

Then reference each by name in your grain definitions:

grain { persist "Cache" ... }
grain { persist "Archive" ... }

siloConfig {
useLocalhostClustering
addMemoryStorage "Default"
addMemoryStreams "StreamProvider"
}

A PubSubStore memory storage is automatically added if not already configured.

For durable streams backed by queues (Event Hubs, Redis, etc.):

siloConfig {
addPersistentStreams "MyStreams" adapterFactory configurator
}

Use the StreamProviders module:

open Orleans.FSharp.StreamProviders
let connStr = Environment.GetEnvironmentVariable("EVENTHUB_CONNECTION")
let configureFn = StreamProviders.addEventHubStreams "EventHubProvider" connStr "my-hub"
// Apply to siloBuilder directly
configureFn siloBuilder |> ignore
let configureFn = StreamProviders.addAzureQueueStreams "QueueProvider" azureConnStr
configureFn siloBuilder |> ignore

Broadcast channels deliver messages to ALL subscriber grains (fan-out):

siloConfig {
addBroadcastChannel "Notifications"
}

siloConfig { addMemoryReminderService }

Requires Microsoft.Orleans.Reminders.Redis.

siloConfig { addRedisReminderService connStr }
siloConfig {
addCustomReminderService (fun siloBuilder ->
siloBuilder.UseMyReminderService()
)
}

Requires Microsoft.Orleans.Connections.Security.

siloConfig {
useLocalhostClustering
useTls "CN=my-silo-cert"
}
let cert = new X509Certificate2("path/to/cert.pfx", "password")
siloConfig {
useLocalhostClustering
useTlsWithCertificate cert
}
siloConfig {
useLocalhostClustering
useMutualTls "CN=my-silo-cert"
}
siloConfig {
useLocalhostClustering
useMutualTlsWithCertificate cert
}

Warning: Always use valid certificates from a trusted CA in production. Never disable certificate validation in production environments.


Requires Microsoft.Orleans.Dashboard.

siloConfig {
useLocalhostClustering
addDashboard
}
siloConfig {
useLocalhostClustering
addDashboardWithOptions
5000 // counter update interval (ms)
100 // history length
false // hide trace
}

Map the dashboard endpoints in your ASP.NET Core pipeline with MapOrleansDashboard().


siloConfig {
useLocalhostClustering
enableHealthChecks
}

Then map the health check endpoints in your ASP.NET Core pipeline:

app.MapHealthChecks("/health") |> ignore

Run code when the silo starts:

siloConfig {
useLocalhostClustering
addStartupTask (fun sp ct ->
task {
let logger = sp.GetRequiredService<ILogger<_>>()
logger.LogInformation("Silo started!")
} :> Task)
}

Multiple startup tasks accumulate and run in registration order.


Control how grains of different versions communicate during rolling upgrades:

open Orleans.FSharp.Versioning
siloConfig {
useLocalhostClustering
useGrainVersioning BackwardCompatible AllCompatibleVersions
}

Compatibility strategies:

StrategyDescription
BackwardCompatibleOlder versions can call newer (default)
StrictVersionOnly exact version matches
AllVersionsAll versions interoperate

Version selector strategies:

StrategyDescription
AllCompatibleVersionsRandom among compatible (default)
LatestVersionAlways activate latest
MinimumVersionAlways activate oldest

Set the global idle timeout before grain deactivation:

siloConfig {
useLocalhostClustering
grainCollectionAge (TimeSpan.FromMinutes 30.)
}

For per-grain timeouts, use deactivationTimeout in the grain { } CE.


siloConfig {
useLocalhostClustering
clusterId "my-cluster"
serviceId "my-service"
siloName "silo-1"
}
siloConfig {
useLocalhostClustering
siloPort 11111
gatewayPort 30000
advertisedIpAddress "10.0.0.1"
}

Intercept calls arriving at a grain:

open Orleans.FSharp
let loggingFilter =
Filter.incoming (fun ctx ->
task {
printfn "Incoming call: %s" (FilterContext.methodName ctx)
do! ctx.Invoke()
printfn "Call completed"
})
siloConfig {
useLocalhostClustering
addIncomingFilter loggingFilter
}

Intercept calls made from a grain to another grain:

let tracingFilter =
Filter.outgoing (fun ctx ->
task {
// Add tracing headers
do! ctx.Invoke()
})
siloConfig {
useLocalhostClustering
addOutgoingFilter tracingFilter
}
let timingFilter =
Filter.incomingWithAround
(fun ctx -> task { printfn "Before %s" (FilterContext.methodName ctx) })
(fun ctx -> task { printfn "After %s" (FilterContext.methodName ctx) })

GrainServices run on every silo. Use them for background processing:

siloConfig {
useLocalhostClustering
addGrainService typeof<MyBackgroundService>
}

Register custom services with the host’s DI container:

siloConfig {
useLocalhostClustering
configureServices (fun services ->
services.AddSingleton<IMyService, MyService>() |> ignore
services.AddHttpClient() |> ignore)
}

Wire Serilog as the logging provider:

siloConfig {
useLocalhostClustering
useSerilog
}

open System
open Orleans.FSharp
open Orleans.FSharp.Runtime
open Orleans.FSharp.Versioning
let redisConn = Environment.GetEnvironmentVariable("REDIS_CONNECTION")
let azureConn = Environment.GetEnvironmentVariable("AZURE_STORAGE_CONNECTION")
let config = siloConfig {
// Clustering
addRedisClustering redisConn
clusterId "production"
serviceId "my-app"
// Storage
addRedisStorage "Default" redisConn
addAzureBlobStorage "Archive" azureConn
// Streaming
addMemoryStreams "Events"
addBroadcastChannel "Notifications"
// Reminders
addRedisReminderService redisConn
// Security
useMutualTls "CN=orleans-silo"
// Observability
enableHealthChecks
addDashboard
useSerilog
// Services
configureServices (fun services ->
services.AddHttpClient() |> ignore)
// Versioning
useGrainVersioning BackwardCompatible LatestVersion
// Endpoints
siloPort 11111
gatewayPort 30000
// Lifecycle
grainCollectionAge (TimeSpan.FromHours 2.)
addStartupTask (fun sp ct ->
task { printfn "Silo started" } :> Threading.Tasks.Task)
}