-
Notifications
You must be signed in to change notification settings - Fork 345
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add .NET client for pub/sub support - streaming subscriptions (#1381)
* Building out Dapr.Messaging and test project for streaming pubsub subscriptions Signed-off-by: Whit Waldo <[email protected]> * Added copyright notices Signed-off-by: Whit Waldo <[email protected]> * Minor stylistic updates Signed-off-by: Whit Waldo <[email protected]> * Added generic client builder to support publish/subscribe client builder Signed-off-by: Whit Waldo <[email protected]> * Tweaked XML comment Signed-off-by: Whit Waldo <[email protected]> * Added several unit tests for the generic client builder Signed-off-by: Whit Waldo <[email protected]> * Updated to include latest review changes: - Added lock so that while we guarantee the method is called only once, it should be thread-safe now - Marked PublishSubscribeReceiver as internal so its members aren't part of the public API - Updated TopicMessage to use IReadOnlyDictionary Signed-off-by: Whit Waldo <[email protected]> * Switched to interlock exchange instead of lock to slightly simplify code Signed-off-by: Whit Waldo <[email protected]> * Added sample project Signed-off-by: Whit Waldo <[email protected]> * Minor changes to unit test Signed-off-by: Whit Waldo <[email protected]> * Deleted protos folder Signed-off-by: Whit Waldo <[email protected]> * Using lowercase protos dir name Signed-off-by: Whit Waldo <[email protected]> * Added registration extension methods Signed-off-by: Whit Waldo <[email protected]> * Updated example to use DI registration Signed-off-by: Whit Waldo <[email protected]> * Added default cancellation token Signed-off-by: Whit Waldo <[email protected]> * Passing stream into method instead of creating it twice Signed-off-by: Whit Waldo <[email protected]> --------- Signed-off-by: Whit Waldo <[email protected]>
- Loading branch information
Showing
19 changed files
with
1,011 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,51 @@ | ||
<Project> | ||
<PropertyGroup> | ||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> | ||
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0" /> | ||
<PackageVersion Include="coverlet.collector" Version="6.0.2" /> | ||
<PackageVersion Include="coverlet.msbuild" Version="6.0.2" /> | ||
<PackageVersion Include="FluentAssertions" Version="5.9.0" /> | ||
<PackageVersion Include="GitHubActionsTestLogger" Version="1.1.2" /> | ||
<PackageVersion Include="Google.Api.CommonProtos" Version="2.2.0" /> | ||
<PackageVersion Include="Google.Protobuf" Version="3.28.2" /> | ||
<PackageVersion Include="Grpc.AspNetCore" Version="2.66.0" /> | ||
<PackageVersion Include="Grpc.Core.Testing" Version="2.46.6" /> | ||
<PackageVersion Include="Grpc.Net.Client" Version="2.66.0" /> | ||
<PackageVersion Include="Grpc.Net.ClientFactory" Version="2.66.0" /> | ||
<PackageVersion Include="Grpc.Tools" Version="2.67.0" /> | ||
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.35" /> | ||
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="6.0.35" /> | ||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" /> | ||
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="4.8.0" /> | ||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" /> | ||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing" Version="1.1.2" /> | ||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit" Version="1.1.2" /> | ||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.8.0" /> | ||
<PackageVersion Include="Microsoft.DurableTask.Client.Grpc" Version="1.3.0" /> | ||
<PackageVersion Include="Microsoft.DurableTask.Worker.Grpc" Version="1.3.0" /> | ||
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="6.0.1" /> | ||
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" /> | ||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" /> | ||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" /> | ||
<PackageVersion Include="Microsoft.Extensions.Http" Version="6.0.0" /> | ||
<PackageVersion Include="Microsoft.Extensions.Logging" Version="6.0.0" /> | ||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" /> | ||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="16.8.3" /> | ||
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" /> | ||
<PackageVersion Include="MinVer" Version="2.3.0" /> | ||
<PackageVersion Include="Moq" Version="4.20.72" /> | ||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" /> | ||
<PackageVersion Include="protobuf-net.Grpc.AspNetCore" Version="1.2.2" /> | ||
<PackageVersion Include="Serilog.AspNetCore" Version="6.1.0" /> | ||
<PackageVersion Include="Serilog.Sinks.Console" Version="4.1.0" /> | ||
<PackageVersion Include="Serilog.Sinks.File" Version="5.0.0" /> | ||
<PackageVersion Include="System.Formats.Asn1" Version="6.0.1" /> | ||
<PackageVersion Include="System.Text.Json" Version="8.0.5" /> | ||
<PackageVersion Include="xunit" Version="2.9.2" /> | ||
<PackageVersion Include="xunit.extensibility.core" Version="2.9.2" /> | ||
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" /> | ||
</ItemGroup> | ||
<PropertyGroup> | ||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> | ||
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0" /> | ||
<PackageVersion Include="coverlet.collector" Version="6.0.2" /> | ||
<PackageVersion Include="coverlet.msbuild" Version="6.0.2" /> | ||
<PackageVersion Include="FluentAssertions" Version="5.9.0" /> | ||
<PackageVersion Include="GitHubActionsTestLogger" Version="1.1.2" /> | ||
<PackageVersion Include="Google.Api.CommonProtos" Version="2.2.0" /> | ||
<PackageVersion Include="Google.Protobuf" Version="3.28.2" /> | ||
<PackageVersion Include="Grpc.AspNetCore" Version="2.66.0" /> | ||
<PackageVersion Include="Grpc.Core.Testing" Version="2.46.6" /> | ||
<PackageVersion Include="Grpc.Net.Client" Version="2.66.0" /> | ||
<PackageVersion Include="Grpc.Net.ClientFactory" Version="2.66.0" /> | ||
<PackageVersion Include="Grpc.Tools" Version="2.67.0" /> | ||
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.35" /> | ||
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="6.0.35" /> | ||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" /> | ||
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="4.8.0" /> | ||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" /> | ||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing" Version="1.1.2" /> | ||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit" Version="1.1.2" /> | ||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.8.0" /> | ||
<PackageVersion Include="Microsoft.DurableTask.Client.Grpc" Version="1.3.0" /> | ||
<PackageVersion Include="Microsoft.DurableTask.Worker.Grpc" Version="1.3.0" /> | ||
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="6.0.1" /> | ||
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" /> | ||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" /> | ||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" /> | ||
<PackageVersion Include="Microsoft.Extensions.Logging" Version="6.0.0" /> | ||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.4" /> | ||
<PackageVersion Include="Microsoft.Extensions.Http" Version="6.0.0" /> | ||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="16.8.3" /> | ||
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" /> | ||
<PackageVersion Include="MinVer" Version="2.3.0" /> | ||
<PackageVersion Include="Moq" Version="4.20.72" /> | ||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" /> | ||
<PackageVersion Include="protobuf-net.Grpc.AspNetCore" Version="1.2.2" /> | ||
<PackageVersion Include="Serilog.AspNetCore" Version="6.1.0" /> | ||
<PackageVersion Include="Serilog.Sinks.Console" Version="4.1.0" /> | ||
<PackageVersion Include="Serilog.Sinks.File" Version="5.0.0" /> | ||
<PackageVersion Include="System.Formats.Asn1" Version="6.0.1" /> | ||
<PackageVersion Include="System.Text.Json" Version="6.0.10" /> | ||
<PackageVersion Include="xunit" Version="2.9.2" /> | ||
<PackageVersion Include="xunit.extensibility.core" Version="2.9.2" /> | ||
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" /> | ||
</ItemGroup> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
examples/Client/PublishSubscribe/StreamingSubscriptionExample/Program.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
using System.Text; | ||
using Dapr.Messaging.PublishSubscribe; | ||
using Dapr.Messaging.PublishSubscribe.Extensions; | ||
|
||
var builder = WebApplication.CreateBuilder(args); | ||
builder.Services.AddDaprPubSubClient(); | ||
var app = builder.Build(); | ||
|
||
//Process each message returned from the subscription | ||
Task<TopicResponseAction> HandleMessageAsync(TopicMessage message, CancellationToken cancellationToken = default) | ||
{ | ||
try | ||
{ | ||
//Do something with the message | ||
Console.WriteLine(Encoding.UTF8.GetString(message.Data.Span)); | ||
return Task.FromResult(TopicResponseAction.Success); | ||
} | ||
catch | ||
{ | ||
return Task.FromResult(TopicResponseAction.Retry); | ||
} | ||
} | ||
|
||
var messagingClient = app.Services.GetRequiredService<DaprPublishSubscribeClient>(); | ||
|
||
//Create a dynamic streaming subscription and subscribe with a timeout of 30 seconds and 10 seconds for message handling | ||
var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30)); | ||
var subscription = await messagingClient.SubscribeAsync("pubsub", "myTopic", | ||
new DaprSubscriptionOptions(new MessageHandlingPolicy(TimeSpan.FromSeconds(10), TopicResponseAction.Retry)), | ||
HandleMessageAsync, cancellationTokenSource.Token); | ||
|
||
await Task.Delay(TimeSpan.FromMinutes(1)); | ||
|
||
//When you're done with the subscription, simply dispose of it | ||
await subscription.DisposeAsync(); |
14 changes: 14 additions & 0 deletions
14
.../Client/PublishSubscribe/StreamingSubscriptionExample/StreamingSubscriptionExample.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<Project Sdk="Microsoft.NET.Sdk.Web"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net6.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\..\..\src\Dapr.Messaging\Dapr.Messaging.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<Description>This package contains the reference assemblies for developing messaging services using Dapr.</Description> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<PackageId>Dapr.Messaging</PackageId> | ||
<Title>Dapr Messaging SDK</Title> | ||
<Description>Dapr Messaging SDK for building applications that utilize messaging components.</Description> | ||
<VersionSuffix>alpha</VersionSuffix> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Dapr.Common\Dapr.Common.csproj" /> | ||
<ProjectReference Include="..\Dapr.Protos\Dapr.Protos.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
31 changes: 31 additions & 0 deletions
31
src/Dapr.Messaging/PublishSubscribe/DaprPublishSubscribeClient.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// ------------------------------------------------------------------------ | ||
// Copyright 2024 The Dapr Authors | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// ------------------------------------------------------------------------ | ||
|
||
namespace Dapr.Messaging.PublishSubscribe; | ||
|
||
/// <summary> | ||
/// The base implementation of a Dapr pub/sub client. | ||
/// </summary> | ||
public abstract class DaprPublishSubscribeClient | ||
{ | ||
/// <summary> | ||
/// Dynamically subscribes to a Publish/Subscribe component and topic. | ||
/// </summary> | ||
/// <param name="pubSubName">The name of the Publish/Subscribe component.</param> | ||
/// <param name="topicName">The name of the topic to subscribe to.</param> | ||
/// <param name="options">Configuration options.</param> | ||
/// <param name="messageHandler">The delegate reflecting the action to take upon messages received by the subscription.</param> | ||
/// <param name="cancellationToken">Cancellation token.</param> | ||
/// <returns></returns> | ||
public abstract Task<IAsyncDisposable> SubscribeAsync(string pubSubName, string topicName, DaprSubscriptionOptions options, TopicMessageHandler messageHandler, CancellationToken cancellationToken = default); | ||
} |
47 changes: 47 additions & 0 deletions
47
src/Dapr.Messaging/PublishSubscribe/DaprPublishSubscribeClientBuilder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// ------------------------------------------------------------------------ | ||
// Copyright 2024 The Dapr Authors | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// ------------------------------------------------------------------------ | ||
|
||
using Dapr.Common; | ||
using Microsoft.Extensions.Configuration; | ||
using Autogenerated = Dapr.Client.Autogen.Grpc.v1; | ||
|
||
namespace Dapr.Messaging.PublishSubscribe; | ||
|
||
/// <summary> | ||
/// Builds a <see cref="DaprPublishSubscribeClient"/>. | ||
/// </summary> | ||
public sealed class DaprPublishSubscribeClientBuilder : DaprGenericClientBuilder<DaprPublishSubscribeClient> | ||
{ | ||
/// <summary> | ||
/// Used to initialize a new instance of the <see cref="DaprPublishSubscribeClientBuilder"/>. | ||
/// </summary> | ||
/// <param name="configuration">An optional instance of <see cref="IConfiguration"/>.</param> | ||
public DaprPublishSubscribeClientBuilder(IConfiguration? configuration = null) : base(configuration) | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Builds the client instance from the properties of the builder. | ||
/// </summary> | ||
/// <returns>The Dapr client instance.</returns> | ||
/// <summary> | ||
/// Builds the client instance from the properties of the builder. | ||
/// </summary> | ||
public override DaprPublishSubscribeClient Build() | ||
{ | ||
var daprClientDependencies = BuildDaprClientDependencies(); | ||
var client = new Autogenerated.Dapr.DaprClient(daprClientDependencies.channel); | ||
|
||
return new DaprPublishSubscribeGrpcClient(client); | ||
} | ||
} |
49 changes: 49 additions & 0 deletions
49
src/Dapr.Messaging/PublishSubscribe/DaprPublishSubscribeGrpcClient.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// ------------------------------------------------------------------------ | ||
// Copyright 2024 The Dapr Authors | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// ------------------------------------------------------------------------ | ||
|
||
using P = Dapr.Client.Autogen.Grpc.v1.Dapr; | ||
|
||
namespace Dapr.Messaging.PublishSubscribe; | ||
|
||
/// <summary> | ||
/// A client for interacting with the Dapr endpoints. | ||
/// </summary> | ||
internal sealed class DaprPublishSubscribeGrpcClient : DaprPublishSubscribeClient | ||
{ | ||
private readonly P.DaprClient daprClient; | ||
|
||
/// <summary> | ||
/// Creates a new instance of a <see cref="DaprPublishSubscribeGrpcClient"/> | ||
/// </summary> | ||
public DaprPublishSubscribeGrpcClient(P.DaprClient client) | ||
{ | ||
daprClient = client; | ||
} | ||
|
||
/// <summary> | ||
/// Dynamically subscribes to a Publish/Subscribe component and topic. | ||
/// </summary> | ||
/// <param name="pubSubName">The name of the Publish/Subscribe component.</param> | ||
/// <param name="topicName">The name of the topic to subscribe to.</param> | ||
/// <param name="options">Configuration options.</param> | ||
/// <param name="messageHandler">The delegate reflecting the action to take upon messages received by the subscription.</param> | ||
/// <param name="cancellationToken">Cancellation token.</param> | ||
/// <returns></returns> | ||
public override async Task<IAsyncDisposable> SubscribeAsync(string pubSubName, string topicName, DaprSubscriptionOptions options, TopicMessageHandler messageHandler, CancellationToken cancellationToken = default) | ||
{ | ||
var receiver = new PublishSubscribeReceiver(pubSubName, topicName, options, messageHandler, daprClient); | ||
await receiver.SubscribeAsync(cancellationToken); | ||
return receiver; | ||
} | ||
} | ||
|
Oops, something went wrong.