Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Distinguish Orleans hosts & clients, parameterize CluserId/ServiceId, improve playground app #3433

Merged
merged 3 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions Aspire.sln
Original file line number Diff line number Diff line change
Expand Up @@ -433,26 +433,26 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Qdrant.ApiService", "playgr
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.Hosting.Azure.EventHubs", "src\Aspire.Hosting.Azure.EventHubs\Aspire.Hosting.Azure.EventHubs.csproj", "{2580B014-E7FE-48D9-BE40-E90604365F0E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.Hosting.Tests.SharedShim", "tests\Aspire.Hosting.Tests.SharedShim\Aspire.Hosting.Tests.SharedShim.csproj", "{74644A4D-8F61-4314-B6E8-5CE3802CD6C2}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.Hosting.Tests.SharedShim", "tests\Aspire.Hosting.Tests.SharedShim\Aspire.Hosting.Tests.SharedShim.csproj", "{74644A4D-8F61-4314-B6E8-5CE3802CD6C2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.Hosting.Azure.KeyVault", "src\Aspire.Hosting.Azure.KeyVault\Aspire.Hosting.Azure.KeyVault.csproj", "{427F4D7C-8969-4015-AD1A-5EFFE921A184}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.Qdrant.Client", "src\Components\Aspire.Qdrant.Client\Aspire.Qdrant.Client.csproj", "{E0E1B557-D3CF-4446-B993-E5CE719234FB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.Qdrant.Client.Tests", "tests\Aspire.Qdrant.Client.Tests\Aspire.Qdrant.Client.Tests.csproj", "{A9CFA376-0C90-4231-9152-FBF14065195A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.Qdrant.Client.Tests", "tests\Aspire.Qdrant.Client.Tests\Aspire.Qdrant.Client.Tests.csproj", "{A9CFA376-0C90-4231-9152-FBF14065195A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.Azure.Messaging.EventHubs.Tests", "tests\Aspire.Azure.Messaging.EventHubs.Tests\Aspire.Azure.Messaging.EventHubs.Tests.csproj", "{8191109E-130C-47F3-B84E-82070A6CD269}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.Azure.Messaging.EventHubs.Tests", "tests\Aspire.Azure.Messaging.EventHubs.Tests\Aspire.Azure.Messaging.EventHubs.Tests.csproj", "{8191109E-130C-47F3-B84E-82070A6CD269}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrleansClient", "playground\orleans\OrleansClient\OrleansClient.csproj", "{906B5687-31AD-4364-AD9F-B4B26113462D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrleansContracts", "playground\orleans\OrleansContracts\OrleansContracts.csproj", "{75760E8A-7025-4F6A-B152-6622688D0E7D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A9CFA376-0C90-4231-9152-FBF14065195A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A9CFA376-0C90-4231-9152-FBF14065195A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A9CFA376-0C90-4231-9152-FBF14065195A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A9CFA376-0C90-4231-9152-FBF14065195A}.Release|Any CPU.Build.0 = Release|Any CPU
{B52DCF1A-465D-4E92-A68A-0EE1A9ED49DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B52DCF1A-465D-4E92-A68A-0EE1A9ED49DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B52DCF1A-465D-4E92-A68A-0EE1A9ED49DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -1157,16 +1157,27 @@ Global
{E0E1B557-D3CF-4446-B993-E5CE719234FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0E1B557-D3CF-4446-B993-E5CE719234FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0E1B557-D3CF-4446-B993-E5CE719234FB}.Release|Any CPU.Build.0 = Release|Any CPU
{A9CFA376-0C90-4231-9152-FBF14065195A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A9CFA376-0C90-4231-9152-FBF14065195A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A9CFA376-0C90-4231-9152-FBF14065195A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A9CFA376-0C90-4231-9152-FBF14065195A}.Release|Any CPU.Build.0 = Release|Any CPU
{8191109E-130C-47F3-B84E-82070A6CD269}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8191109E-130C-47F3-B84E-82070A6CD269}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8191109E-130C-47F3-B84E-82070A6CD269}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8191109E-130C-47F3-B84E-82070A6CD269}.Release|Any CPU.Build.0 = Release|Any CPU
{906B5687-31AD-4364-AD9F-B4B26113462D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{906B5687-31AD-4364-AD9F-B4B26113462D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{906B5687-31AD-4364-AD9F-B4B26113462D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{906B5687-31AD-4364-AD9F-B4B26113462D}.Release|Any CPU.Build.0 = Release|Any CPU
{75760E8A-7025-4F6A-B152-6622688D0E7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{75760E8A-7025-4F6A-B152-6622688D0E7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{75760E8A-7025-4F6A-B152-6622688D0E7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75760E8A-7025-4F6A-B152-6622688D0E7D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{A9CFA376-0C90-4231-9152-FBF14065195A} = {4981B3A5-4AFD-4191-BF7D-8692D9783D60}
{B52DCF1A-465D-4E92-A68A-0EE1A9ED49DF} = {B80354C7-BE58-43F6-8928-9F3A74AB7F47}
{E958BE04-81C2-434C-9E6C-CA145A2B8218} = {A68BA1A5-1604-433D-9778-DC0199831C2A}
{C1D595AD-FFFD-4E52-AAF6-8DD8C4BD67F1} = {A68BA1A5-1604-433D-9778-DC0199831C2A}
Expand Down Expand Up @@ -1371,7 +1382,10 @@ Global
{74644A4D-8F61-4314-B6E8-5CE3802CD6C2} = {4981B3A5-4AFD-4191-BF7D-8692D9783D60}
{427F4D7C-8969-4015-AD1A-5EFFE921A184} = {77CFE74A-32EE-400C-8930-5025E8555256}
{E0E1B557-D3CF-4446-B993-E5CE719234FB} = {27381127-6C45-4B4C-8F18-41FF48DFE4B2}
{A9CFA376-0C90-4231-9152-FBF14065195A} = {4981B3A5-4AFD-4191-BF7D-8692D9783D60}
{8191109E-130C-47F3-B84E-82070A6CD269} = {4981B3A5-4AFD-4191-BF7D-8692D9783D60}
{906B5687-31AD-4364-AD9F-B4B26113462D} = {8BAF2119-8370-4E9E-A887-D92506F8C727}
{75760E8A-7025-4F6A-B152-6622688D0E7D} = {8BAF2119-8370-4E9E-A887-D92506F8C727}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6DCEDFEC-988E-4CB3-B45B-191EB5086E0C}
Expand Down
2 changes: 2 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@
<PackageVersion Include="Dapr.AspNetCore" Version="1.13.0" />
<PackageVersion Include="Microsoft.Orleans.Clustering.AzureStorage" Version="8.1.0-nightly.20240126.1" />
<PackageVersion Include="Microsoft.Orleans.Persistence.AzureStorage" Version="8.1.0-nightly.20240126.1" />
<PackageVersion Include="Microsoft.Orleans.Client" Version="8.1.0-nightly.20240126.1" />
<PackageVersion Include="Microsoft.Orleans.Server" Version="8.1.0-nightly.20240126.1" />
<PackageVersion Include="Microsoft.Orleans.Sdk" Version="8.1.0-nightly.20240126.1" />
<!-- Pinned version for Component Governance - Remove when root dependencies are updated -->
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<!-- Introduced by Microsoft.Azure.Cosmos, https://github.com/Azure/azure-cosmos-dotnet-v3/issues/4302 -->
Expand Down
1 change: 1 addition & 0 deletions playground/orleans/OrleansAppHost/OrleansAppHost.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<ProjectReference Include="..\..\..\src\Aspire.Hosting.Azure.Storage\Aspire.Hosting.Azure.Storage.csproj" IsAspireProjectResource="false" />

<ProjectReference Include="..\OrleansServer\OrleansServer.csproj" />
<ProjectReference Include="..\OrleansClient\OrleansClient.csproj" />
</ItemGroup>

</Project>
4 changes: 4 additions & 0 deletions playground/orleans/OrleansAppHost/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@

builder.AddProject<Projects.OrleansServer>("silo")
.WithReference(orleans)
.WithReplicas(3);

builder.AddProject<Projects.OrleansClient>("frontend")
.WithReference(orleans.AsClient())
.WithExternalHttpEndpoints()
.WithReplicas(3);

Expand Down
21 changes: 21 additions & 0 deletions playground/orleans/OrleansClient/OrleansClient.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Orleans.Client" />
<PackageReference Include="Microsoft.Orleans.Clustering.AzureStorage" />
<ProjectReference Include="..\..\..\src\Components\Aspire.Azure.Data.Tables\Aspire.Azure.Data.Tables.csproj" />
<ProjectReference Include="..\OrleansContracts\OrleansContracts.csproj" />
<ProjectReference Include="..\OrleansServiceDefaults\OrleansServiceDefaults.csproj" />
</ItemGroup>

</Project>
25 changes: 25 additions & 0 deletions playground/orleans/OrleansClient/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using OrleansContracts;

var builder = WebApplication.CreateBuilder(args);

builder.AddServiceDefaults();
builder.AddKeyedAzureTableClient("clustering");
builder.UseOrleansClient();

var app = builder.Build();

app.MapGet("/counter/{grainId}", async (IClusterClient client, string grainId) =>
{
var grain = client.GetGrain<ICounterGrain>(grainId);
return await grain.Get();
});

app.MapPost("/counter/{grainId}", async (IClusterClient client, string grainId) =>
{
var grain = client.GetGrain<ICounterGrain>(grainId);
return await grain.Increment();
});

app.UseFileServer();

await app.RunAsync();
12 changes: 12 additions & 0 deletions playground/orleans/OrleansClient/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"profiles": {
"OrleansServer": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:52222"
}
}
}
8 changes: 8 additions & 0 deletions playground/orleans/OrleansClient/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
10 changes: 10 additions & 0 deletions playground/orleans/OrleansContracts/ICounterGrain.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace OrleansContracts;

public interface ICounterGrain : IGrainWithStringKey
{
ValueTask<int> Increment();
ValueTask<int> Get();
}
12 changes: 12 additions & 0 deletions playground/orleans/OrleansContracts/OrleansContracts.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Orleans.Sdk" />
</ItemGroup>
</Project>
1 change: 1 addition & 0 deletions playground/orleans/OrleansServer/OrleansServer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<PackageReference Include="Microsoft.Orleans.Clustering.AzureStorage" />
<ProjectReference Include="..\..\..\src\Components\Aspire.Azure.Data.Tables\Aspire.Azure.Data.Tables.csproj" />
<ProjectReference Include="..\..\..\src\Components\Aspire.Azure.Storage.Blobs\Aspire.Azure.Storage.Blobs.csproj" />
<ProjectReference Include="..\OrleansContracts\OrleansContracts.csproj" />
<ProjectReference Include="..\OrleansServiceDefaults\OrleansServiceDefaults.csproj" />
</ItemGroup>

Expand Down
21 changes: 2 additions & 19 deletions playground/orleans/OrleansServer/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Orleans.Runtime;
using OrleansContracts;

var builder = WebApplication.CreateBuilder(args);

Expand All @@ -9,28 +10,10 @@

var app = builder.Build();

app.MapGet("/counter/{grainId}", async (IClusterClient client, string grainId) =>
{
var grain = client.GetGrain<ICounterGrain>(grainId);
return await grain.Get();
});

app.MapPost("/counter/{grainId}", async (IClusterClient client, string grainId) =>
{
var grain = client.GetGrain<ICounterGrain>(grainId);
return await grain.Increment();
});

app.UseFileServer();
app.MapGet("/", () => "OK");

await app.RunAsync();

public interface ICounterGrain : IGrainWithStringKey
{
ValueTask<int> Increment();
ValueTask<int> Get();
}

public sealed class CounterGrain(
[PersistentState("count")] IPersistentState<int> count) : ICounterGrain
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
"profiles": {
"OrleansServer": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:56297;http://localhost:56298"
"applicationUrl": "https://localhost:51111"
}
}
}
}
35 changes: 28 additions & 7 deletions src/Aspire.Hosting.Orleans/OrleansService.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,55 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.ApplicationModel;

namespace Aspire.Hosting.Orleans;

/// <summary>
/// Describes an Orleans service.
/// </summary>
/// <param name="builder">The distributed application builder.</param>
/// <param name="name">The service name.</param>
public class OrleansService(IDistributedApplicationBuilder builder, string name)
public class OrleansService
{
/// <summary>Initializes a new <see cref="OrleansService"/> instance.</summary>
/// <param name="builder">The distributed application builder.</param>
/// <param name="name">The service name.</param>
public OrleansService(IDistributedApplicationBuilder builder, string name)
{
Name = name;
Builder = builder;
ServiceId = ParameterResourceBuilderExtensions.CreateGeneratedParameter(builder, $"{name}-service-id", secret: false, new GenerateParameterDefault
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eerhardt this API is kinda crazy 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestions on making it better?

{
Upper = false,
Special = false,
MinLength = 25
});
ClusterId = ParameterResourceBuilderExtensions.CreateGeneratedParameter(builder, $"{name}-cluster-id", secret: false, new GenerateParameterDefault
{
Upper = false,
Special = false,
MinLength = 25
});
}

/// <summary>
/// Gets the name of the service.
/// </summary>
public string Name { get; } = name;
public string Name { get; }

/// <summary>
/// Gets the distributed application builder.
/// </summary>
public IDistributedApplicationBuilder Builder { get; } = builder;
public IDistributedApplicationBuilder Builder { get; }

/// <summary>
/// Gets or sets the service identifier.
/// </summary>
public string? ServiceId { get; set; }
internal object ServiceId { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why object?

Suggested change
internal object ServiceId { get; set; }
internal ParameterResource ServiceId { get; set; }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's either a parameter or a hard-coded string value.. I made it internal so at least this detail doesn't leak.

See WithServiceId and WithClusterId

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's either a parameter or a hard-coded string value.

Might be good sticking that comment in here.


/// <summary>
/// Gets or sets the cluster identifier.
/// </summary>
public string? ClusterId { get; set; } = Guid.NewGuid().ToString("N");
internal object ClusterId { get; set; }

/// <summary>
/// Gets or sets the clustering provider.
Expand Down
16 changes: 16 additions & 0 deletions src/Aspire.Hosting.Orleans/OrleansServiceClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Aspire.Hosting.Orleans;

/// <summary>
/// Represents an Orleans client.
/// </summary>
/// <param name="service">The Orleans service which this client connects to.</param>
public sealed class OrleansServiceClient(OrleansService service)
{
/// <summary>
/// Gets the Orleans service which this client will connect to.
/// </summary>
public OrleansService Service { get; } = service;
}
28 changes: 28 additions & 0 deletions src/Aspire.Hosting.Orleans/OrleansServiceClientExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Orleans;

namespace Aspire.Hosting;

/// <summary>
/// Extension methods for <see cref="OrleansServiceClient"/>.
/// </summary>
public static class OrleansServiceClientExtensions
{
/// <summary>
/// Adds an Orleans client to the resource.
/// </summary>
/// <param name="builder">The builder on which add the Orleans service builder.</param>
/// <param name="orleansServiceClient">The Orleans service client, containing clustering, etc.</param>
/// <returns>The resource builder.</returns>
/// <exception cref="InvalidOperationException">Clustering has not been configured.</exception>
public static IResourceBuilder<T> WithReference<T>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When would I use WithReference(OrleansServiceClient) over using WithReference(OrleansService)?

Is it confusing to have both? What's the difference between:

builder.AddProject<Projects.OrleansServer>("silo")
       .WithReference(orleans);

and

builder.AddProject<Projects.OrleansClient>("frontend")
       .WithReference(orleans.AsClient());

?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You use the service one for projects with an Orleans server and the client one with the Orleans clients. Their configuration follows the same format, but servers have more (storage, etc)

this IResourceBuilder<T> builder,
OrleansServiceClient orleansServiceClient)
where T : IResourceWithEnvironment
{
return builder.WithOrleansReference(orleansServiceClient.Service, isSilo: false);
}
}
Loading
Loading