From af4c37649eb60a978ef9fa9e868c6983c759a0cf Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Mon, 24 Aug 2026 11:39:54 -0700 Subject: [PATCH 1/2] refactor(runtime): include file grain storage --- Orleans.slnx | 5 +- .../content/docs/resources/nuget-packages.md | 3 +- .../src/data/external-link-allowlist.json | 1 - .../src/data/unpublished-api-packages.json | 1 - .../Orleans.Persistence.FileStorage.csproj | 25 -------- .../Orleans.Persistence.FileStorage/README.md | 64 ------------------- .../FileStorage}/FileGrainStorage.cs | 0 .../FileStorage}/FileGrainStorageFactory.cs | 0 .../FileStorage}/FileGrainStorageOptions.cs | 0 .../FileStorage}/FileSiloBuilderExtensions.cs | 0 src/Orleans.Runtime/README.md | 14 ++++ src/api/Orleans.Runtime/Orleans.Runtime.cs | 34 ++++++++++ .../FileGrainStorageBoundaryTests.cs | 0 .../FileGrainStorageConformanceTests.cs | 0 .../FileGrainStorageOptionsTests.cs | 0 .../FileGrainStorageTestFixture.cs | 0 .../FileSiloBuilderExtensionsTests.cs | 0 ...leans.Persistence.FileStorage.Tests.csproj | 2 +- .../RecordingGrainStorageSerializer.cs | 0 19 files changed, 52 insertions(+), 97 deletions(-) delete mode 100644 src/File/Orleans.Persistence.FileStorage/Orleans.Persistence.FileStorage.csproj delete mode 100644 src/File/Orleans.Persistence.FileStorage/README.md rename src/{File/Orleans.Persistence.FileStorage => Orleans.Runtime/Persistence/FileStorage}/FileGrainStorage.cs (100%) rename src/{File/Orleans.Persistence.FileStorage => Orleans.Runtime/Persistence/FileStorage}/FileGrainStorageFactory.cs (100%) rename src/{File/Orleans.Persistence.FileStorage => Orleans.Runtime/Persistence/FileStorage}/FileGrainStorageOptions.cs (100%) rename src/{File/Orleans.Persistence.FileStorage => Orleans.Runtime/Persistence/FileStorage}/FileSiloBuilderExtensions.cs (100%) rename test/{Extensions => }/Orleans.Persistence.FileStorage.Tests/FileGrainStorageBoundaryTests.cs (100%) rename test/{Extensions => }/Orleans.Persistence.FileStorage.Tests/FileGrainStorageConformanceTests.cs (100%) rename test/{Extensions => }/Orleans.Persistence.FileStorage.Tests/FileGrainStorageOptionsTests.cs (100%) rename test/{Extensions => }/Orleans.Persistence.FileStorage.Tests/FileGrainStorageTestFixture.cs (100%) rename test/{Extensions => }/Orleans.Persistence.FileStorage.Tests/FileSiloBuilderExtensionsTests.cs (100%) rename test/{Extensions => }/Orleans.Persistence.FileStorage.Tests/Orleans.Persistence.FileStorage.Tests.csproj (76%) rename test/{Extensions => }/Orleans.Persistence.FileStorage.Tests/RecordingGrainStorageSerializer.cs (100%) diff --git a/Orleans.slnx b/Orleans.slnx index 14b09df46ac..58a75bb99b7 100644 --- a/Orleans.slnx +++ b/Orleans.slnx @@ -103,9 +103,6 @@ - - - @@ -144,6 +141,7 @@ + @@ -182,7 +180,6 @@ - diff --git a/docs/site/src/content/docs/resources/nuget-packages.md b/docs/site/src/content/docs/resources/nuget-packages.md index b610d46bc98..30dca3704f7 100644 --- a/docs/site/src/content/docs/resources/nuget-packages.md +++ b/docs/site/src/content/docs/resources/nuget-packages.md @@ -56,11 +56,12 @@ Every multi-silo production cluster needs a shared membership provider. | [Microsoft.Orleans.Persistence.AzureStorage](https://www.nuget.org/packages/Microsoft.Orleans.Persistence.AzureStorage) | Azure Table and Blob Storage | | [Microsoft.Orleans.Persistence.Cosmos](https://www.nuget.org/packages/Microsoft.Orleans.Persistence.Cosmos) | Azure Cosmos DB | | [Microsoft.Orleans.Persistence.DynamoDB](https://www.nuget.org/packages/Microsoft.Orleans.Persistence.DynamoDB) | Amazon DynamoDB | -| [Microsoft.Orleans.Persistence.FileStorage](https://www.nuget.org/packages/Microsoft.Orleans.Persistence.FileStorage) | Local files for single-silo development and testing | | [Microsoft.Orleans.Persistence.Firestore](https://www.nuget.org/packages/Microsoft.Orleans.Persistence.Firestore) | Google Cloud Firestore | | [Microsoft.Orleans.Persistence.Redis](https://www.nuget.org/packages/Microsoft.Orleans.Persistence.Redis) | Redis | | [Microsoft.Orleans.Persistence.Memory](https://www.nuget.org/packages/Microsoft.Orleans.Persistence.Memory) | Process memory for development and testing | +File storage for local, single-silo development and testing is included in [Microsoft.Orleans.Runtime](https://www.nuget.org/packages/Microsoft.Orleans.Runtime). + Memory persistence distributes records across cluster storage grains but isn't durable or replicated. Use it only when losing records with a hosting process is acceptable. ## Reminders and durable jobs diff --git a/docs/site/src/data/external-link-allowlist.json b/docs/site/src/data/external-link-allowlist.json index 67ec3717000..82e8882d8a9 100644 --- a/docs/site/src/data/external-link-allowlist.json +++ b/docs/site/src/data/external-link-allowlist.json @@ -12,7 +12,6 @@ "https://www.nuget.org/packages/Microsoft.Orleans.Clustering.Firestore": "The new Firestore clustering package is documented but not yet published; remove this entry and its unpublished API-package entry after publication.", "https://www.nuget.org/packages/Microsoft.Orleans.GrainDirectory.Firestore": "The new Firestore grain-directory package is documented but not yet published; remove this entry and its unpublished API-package entry after publication.", "https://www.nuget.org/packages/Microsoft.Orleans.Journaling.Redis": "The new Redis journaling package is documented but not yet published; remove this entry and its unpublished API-package entry after publication.", - "https://www.nuget.org/packages/Microsoft.Orleans.Persistence.FileStorage": "The new file storage persistence package is documented but not yet published; remove this entry and its unpublished API-package entry after publication.", "https://www.nuget.org/packages/Microsoft.Orleans.Persistence.Firestore": "The new Firestore persistence package is documented but not yet published; remove this entry and its unpublished API-package entry after publication.", "https://www.nuget.org/packages/Microsoft.Orleans.Reminders.Firestore": "The new Firestore reminders package is documented but not yet published; remove this entry and its unpublished API-package entry after publication.", "https://www.nuget.org/packages/Microsoft.Orleans.Streaming.Kinesis": "The new Kinesis streaming package is documented but not yet published; remove this entry and its unpublished API-package entry after publication.", diff --git a/docs/site/src/data/unpublished-api-packages.json b/docs/site/src/data/unpublished-api-packages.json index b02adbf910c..c49eb353d4e 100644 --- a/docs/site/src/data/unpublished-api-packages.json +++ b/docs/site/src/data/unpublished-api-packages.json @@ -4,7 +4,6 @@ "Microsoft.Orleans.Clustering.Firestore": "The new provider is awaiting its first NuGet publication.", "Microsoft.Orleans.GrainDirectory.Firestore": "The new provider is awaiting its first NuGet publication.", "Microsoft.Orleans.Journaling.Redis": "The new provider is awaiting its first NuGet publication.", - "Microsoft.Orleans.Persistence.FileStorage": "The new provider is awaiting its first NuGet publication.", "Microsoft.Orleans.Persistence.Firestore": "The new provider is awaiting its first NuGet publication.", "Microsoft.Orleans.Reminders.Firestore": "The new provider is awaiting its first NuGet publication.", "Microsoft.Orleans.Streaming.Kinesis": "The new provider is awaiting its first NuGet publication." diff --git a/src/File/Orleans.Persistence.FileStorage/Orleans.Persistence.FileStorage.csproj b/src/File/Orleans.Persistence.FileStorage/Orleans.Persistence.FileStorage.csproj deleted file mode 100644 index 7d81a7ab87d..00000000000 --- a/src/File/Orleans.Persistence.FileStorage/Orleans.Persistence.FileStorage.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - Microsoft.Orleans.Persistence.FileStorage - Microsoft Orleans File Persistence Provider - Microsoft Orleans persistence providers backed by File Storage - $(PackageTags) FileStorage - $(DefaultTargetFrameworks) - true - README.md - - - - Orleans.Persistence.FileStorage - Orleans.Persistence.FileStorage - $(DefineConstants);PERSISTENCE_FILESTORAGE - - - - - - - - - - diff --git a/src/File/Orleans.Persistence.FileStorage/README.md b/src/File/Orleans.Persistence.FileStorage/README.md deleted file mode 100644 index 42bd194e6e8..00000000000 --- a/src/File/Orleans.Persistence.FileStorage/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# Microsoft Orleans persistence for file storage - -This package stores Orleans grain state as files in a configured directory. It is intended for local, single-silo development and testing. The provider does not replicate state or coordinate access through shared or network filesystems, so it is not production-ready. - -## Install - -```shell -dotnet add package Microsoft.Orleans.Persistence.FileStorage -``` - -## Configure the provider - -```csharp -using Microsoft.Extensions.Hosting; -using Orleans.Hosting; -using Orleans.Persistence.FileStorage; - -var builder = Host.CreateApplicationBuilder(args); - -builder.UseOrleans(siloBuilder => -{ - siloBuilder - .UseLocalhostClustering() - .AddFileGrainStorage( - providerName: "FileStorage", - options => options.RootDirectory = Path.Combine( - AppContext.BaseDirectory, - "Orleans", - "GrainState")); -}); - -await builder.Build().RunAsync(); -``` - -Use the same provider name when injecting persistent state: - -```csharp -using Orleans.Runtime; - -public sealed class MyGrain( - [PersistentState("state", "FileStorage")] - IPersistentState state) : Grain, IMyGrain -{ - public async Task SetData(string data) - { - state.State.Data = data; - state.State.Version++; - await state.WriteStateAsync(); - } - - public Task GetData() => Task.FromResult(state.State.Data); -} - -public sealed class MyGrainState -{ - public string Data { get; set; } = string.Empty; - - public int Version { get; set; } -} -``` - -The provider stores one binary file per grain state record and uses persisted ETags for basic optimistic concurrency checks. It does not coordinate multiple silos or replicate data. - -For Orleans persistence concepts, see [Grain persistence](https://learn.microsoft.com/dotnet/orleans/grains/grain-persistence). diff --git a/src/File/Orleans.Persistence.FileStorage/FileGrainStorage.cs b/src/Orleans.Runtime/Persistence/FileStorage/FileGrainStorage.cs similarity index 100% rename from src/File/Orleans.Persistence.FileStorage/FileGrainStorage.cs rename to src/Orleans.Runtime/Persistence/FileStorage/FileGrainStorage.cs diff --git a/src/File/Orleans.Persistence.FileStorage/FileGrainStorageFactory.cs b/src/Orleans.Runtime/Persistence/FileStorage/FileGrainStorageFactory.cs similarity index 100% rename from src/File/Orleans.Persistence.FileStorage/FileGrainStorageFactory.cs rename to src/Orleans.Runtime/Persistence/FileStorage/FileGrainStorageFactory.cs diff --git a/src/File/Orleans.Persistence.FileStorage/FileGrainStorageOptions.cs b/src/Orleans.Runtime/Persistence/FileStorage/FileGrainStorageOptions.cs similarity index 100% rename from src/File/Orleans.Persistence.FileStorage/FileGrainStorageOptions.cs rename to src/Orleans.Runtime/Persistence/FileStorage/FileGrainStorageOptions.cs diff --git a/src/File/Orleans.Persistence.FileStorage/FileSiloBuilderExtensions.cs b/src/Orleans.Runtime/Persistence/FileStorage/FileSiloBuilderExtensions.cs similarity index 100% rename from src/File/Orleans.Persistence.FileStorage/FileSiloBuilderExtensions.cs rename to src/Orleans.Runtime/Persistence/FileStorage/FileSiloBuilderExtensions.cs diff --git a/src/Orleans.Runtime/README.md b/src/Orleans.Runtime/README.md index 53f07c301ea..c9439bd5bc0 100644 --- a/src/Orleans.Runtime/README.md +++ b/src/Orleans.Runtime/README.md @@ -12,6 +12,20 @@ dotnet add package Microsoft.Orleans.Runtime This package is automatically included when you reference the Orleans Server metapackage. +## File grain storage + +The runtime includes a file-based grain storage provider for local, single-silo development and testing. It stores one binary file per grain state record and uses persisted ETags for optimistic concurrency. + +```csharp +using Orleans.Persistence.FileStorage; + +siloBuilder.AddFileGrainStorage( + options => options.RootDirectory = Path.Combine( + AppContext.BaseDirectory, + "Orleans", + "GrainState")); +``` + ## Example - Configuring a Silo ```csharp diff --git a/src/api/Orleans.Runtime/Orleans.Runtime.cs b/src/api/Orleans.Runtime/Orleans.Runtime.cs index 1da14d96b50..b8b8d347716 100644 --- a/src/api/Orleans.Runtime/Orleans.Runtime.cs +++ b/src/api/Orleans.Runtime/Orleans.Runtime.cs @@ -525,6 +525,40 @@ public GrainClassMap(Serialization.TypeSystem.TypeConverter typeConverter, Syste } } +namespace Orleans.Persistence.FileStorage +{ + public sealed partial class FileGrainStorage : Storage.IGrainStorage, ILifecycleParticipant + { + public FileGrainStorage(string storageName, FileGrainStorageOptions options, Microsoft.Extensions.Options.IOptions clusterOptions, Serialization.Serializers.IActivatorProvider activatorProvider) { } + + public System.Threading.Tasks.Task ClearStateAsync(string stateName, Runtime.GrainId grainId, IGrainState grainState) { throw null; } + + public void Participate(Runtime.ISiloLifecycle lifecycle) { } + + public System.Threading.Tasks.Task ReadStateAsync(string stateName, Runtime.GrainId grainId, IGrainState grainState) { throw null; } + + public System.Threading.Tasks.Task WriteStateAsync(string stateName, Runtime.GrainId grainId, IGrainState grainState) { throw null; } + } + + public sealed partial class FileGrainStorageOptions : Storage.IStorageProviderSerializerOptions + { + public required Storage.IGrainStorageSerializer GrainStorageSerializer { get { throw null; } set { } } + + public required string RootDirectory { get { throw null; } set { } } + } + + public static partial class FileSiloBuilderExtensions + { + public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddFileGrainStorage(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action options) { throw null; } + + public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddFileGrainStorage(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string providerName, System.Action options) { throw null; } + + public static Hosting.ISiloBuilder AddFileGrainStorage(this Hosting.ISiloBuilder builder, System.Action options) { throw null; } + + public static Hosting.ISiloBuilder AddFileGrainStorage(this Hosting.ISiloBuilder builder, string providerName, System.Action options) { throw null; } + } +} + namespace Orleans.Runtime { [GenerateSerializer] diff --git a/test/Extensions/Orleans.Persistence.FileStorage.Tests/FileGrainStorageBoundaryTests.cs b/test/Orleans.Persistence.FileStorage.Tests/FileGrainStorageBoundaryTests.cs similarity index 100% rename from test/Extensions/Orleans.Persistence.FileStorage.Tests/FileGrainStorageBoundaryTests.cs rename to test/Orleans.Persistence.FileStorage.Tests/FileGrainStorageBoundaryTests.cs diff --git a/test/Extensions/Orleans.Persistence.FileStorage.Tests/FileGrainStorageConformanceTests.cs b/test/Orleans.Persistence.FileStorage.Tests/FileGrainStorageConformanceTests.cs similarity index 100% rename from test/Extensions/Orleans.Persistence.FileStorage.Tests/FileGrainStorageConformanceTests.cs rename to test/Orleans.Persistence.FileStorage.Tests/FileGrainStorageConformanceTests.cs diff --git a/test/Extensions/Orleans.Persistence.FileStorage.Tests/FileGrainStorageOptionsTests.cs b/test/Orleans.Persistence.FileStorage.Tests/FileGrainStorageOptionsTests.cs similarity index 100% rename from test/Extensions/Orleans.Persistence.FileStorage.Tests/FileGrainStorageOptionsTests.cs rename to test/Orleans.Persistence.FileStorage.Tests/FileGrainStorageOptionsTests.cs diff --git a/test/Extensions/Orleans.Persistence.FileStorage.Tests/FileGrainStorageTestFixture.cs b/test/Orleans.Persistence.FileStorage.Tests/FileGrainStorageTestFixture.cs similarity index 100% rename from test/Extensions/Orleans.Persistence.FileStorage.Tests/FileGrainStorageTestFixture.cs rename to test/Orleans.Persistence.FileStorage.Tests/FileGrainStorageTestFixture.cs diff --git a/test/Extensions/Orleans.Persistence.FileStorage.Tests/FileSiloBuilderExtensionsTests.cs b/test/Orleans.Persistence.FileStorage.Tests/FileSiloBuilderExtensionsTests.cs similarity index 100% rename from test/Extensions/Orleans.Persistence.FileStorage.Tests/FileSiloBuilderExtensionsTests.cs rename to test/Orleans.Persistence.FileStorage.Tests/FileSiloBuilderExtensionsTests.cs diff --git a/test/Extensions/Orleans.Persistence.FileStorage.Tests/Orleans.Persistence.FileStorage.Tests.csproj b/test/Orleans.Persistence.FileStorage.Tests/Orleans.Persistence.FileStorage.Tests.csproj similarity index 76% rename from test/Extensions/Orleans.Persistence.FileStorage.Tests/Orleans.Persistence.FileStorage.Tests.csproj rename to test/Orleans.Persistence.FileStorage.Tests/Orleans.Persistence.FileStorage.Tests.csproj index 2a325931a04..469476392a0 100644 --- a/test/Extensions/Orleans.Persistence.FileStorage.Tests/Orleans.Persistence.FileStorage.Tests.csproj +++ b/test/Orleans.Persistence.FileStorage.Tests/Orleans.Persistence.FileStorage.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/test/Extensions/Orleans.Persistence.FileStorage.Tests/RecordingGrainStorageSerializer.cs b/test/Orleans.Persistence.FileStorage.Tests/RecordingGrainStorageSerializer.cs similarity index 100% rename from test/Extensions/Orleans.Persistence.FileStorage.Tests/RecordingGrainStorageSerializer.cs rename to test/Orleans.Persistence.FileStorage.Tests/RecordingGrainStorageSerializer.cs From 61fc2bac6761a6c123660b938fd1239dd825aa00 Mon Sep 17 00:00:00 2001 From: Reuben Bond Date: Mon, 24 Aug 2026 12:40:33 -0700 Subject: [PATCH 2/2] docs(runtime): name file storage options argument --- src/Orleans.Runtime/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Orleans.Runtime/README.md b/src/Orleans.Runtime/README.md index c9439bd5bc0..522ef5f021b 100644 --- a/src/Orleans.Runtime/README.md +++ b/src/Orleans.Runtime/README.md @@ -20,7 +20,7 @@ The runtime includes a file-based grain storage provider for local, single-silo using Orleans.Persistence.FileStorage; siloBuilder.AddFileGrainStorage( - options => options.RootDirectory = Path.Combine( + options: options => options.RootDirectory = Path.Combine( AppContext.BaseDirectory, "Orleans", "GrainState"));