diff --git a/CHANGELOG.md b/CHANGELOG.md index dbf11e269..57f6be992 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## vNext +- Added new preview packages, `Microsoft.DurableTask.Client.AzureManaged` and `Microsoft.DurableTask.Worker.AzureManaged` + ### Microsoft.DurableTask.Client - Add new `IDurableTaskClientBuilder AddDurableTaskClient(IServiceCollection, string?)` API diff --git a/src/Client/AzureManaged/DurableTaskSchedulerClientExtensions.cs b/src/Client/AzureManaged/DurableTaskSchedulerClientExtensions.cs index a3fa583f9..b11f450a6 100644 --- a/src/Client/AzureManaged/DurableTaskSchedulerClientExtensions.cs +++ b/src/Client/AzureManaged/DurableTaskSchedulerClientExtensions.cs @@ -59,6 +59,7 @@ public static void UseDurableTaskScheduler( options.EndpointAddress = connectionOptions.EndpointAddress; options.TaskHubName = connectionOptions.TaskHubName; options.Credential = connectionOptions.Credential; + options.AllowInsecureCredentials = connectionOptions.AllowInsecureCredentials; }, configure); } diff --git a/src/Client/AzureManaged/DurableTaskSchedulerClientOptions.cs b/src/Client/AzureManaged/DurableTaskSchedulerClientOptions.cs index 172332cda..9f6829fca 100644 --- a/src/Client/AzureManaged/DurableTaskSchedulerClientOptions.cs +++ b/src/Client/AzureManaged/DurableTaskSchedulerClientOptions.cs @@ -59,12 +59,17 @@ public static DurableTaskSchedulerClientOptions FromConnectionString(string conn /// The connection string to parse. /// A new instance of . internal static DurableTaskSchedulerClientOptions FromConnectionString( - DurableTaskSchedulerConnectionString connectionString) => new() + DurableTaskSchedulerConnectionString connectionString) + { + TokenCredential? credential = GetCredentialFromConnectionString(connectionString); + return new DurableTaskSchedulerClientOptions() { EndpointAddress = connectionString.Endpoint, TaskHubName = connectionString.TaskHubName, - Credential = GetCredentialFromConnectionString(connectionString), + Credential = credential, + AllowInsecureCredentials = credential is null, }; + } /// /// Creates a gRPC channel for communicating with the Durable Task Scheduler service. diff --git a/src/Worker/AzureManaged/DurableTaskSchedulerWorkerExtensions.cs b/src/Worker/AzureManaged/DurableTaskSchedulerWorkerExtensions.cs index 63d19fa00..7a3baa414 100644 --- a/src/Worker/AzureManaged/DurableTaskSchedulerWorkerExtensions.cs +++ b/src/Worker/AzureManaged/DurableTaskSchedulerWorkerExtensions.cs @@ -60,6 +60,7 @@ public static void UseDurableTaskScheduler( options.EndpointAddress = connectionOptions.EndpointAddress; options.TaskHubName = connectionOptions.TaskHubName; options.Credential = connectionOptions.Credential; + options.AllowInsecureCredentials = connectionOptions.AllowInsecureCredentials; }, configure); } diff --git a/src/Worker/AzureManaged/DurableTaskSchedulerWorkerOptions.cs b/src/Worker/AzureManaged/DurableTaskSchedulerWorkerOptions.cs index 67da8cb7a..4a92d91dc 100644 --- a/src/Worker/AzureManaged/DurableTaskSchedulerWorkerOptions.cs +++ b/src/Worker/AzureManaged/DurableTaskSchedulerWorkerOptions.cs @@ -65,12 +65,17 @@ public static DurableTaskSchedulerWorkerOptions FromConnectionString(string conn /// The connection string to parse. /// A new instance of . internal static DurableTaskSchedulerWorkerOptions FromConnectionString( - DurableTaskSchedulerConnectionString connectionString) => new() + DurableTaskSchedulerConnectionString connectionString) + { + TokenCredential? credential = GetCredentialFromConnectionString(connectionString); + return new DurableTaskSchedulerWorkerOptions() { EndpointAddress = connectionString.Endpoint, TaskHubName = connectionString.TaskHubName, - Credential = GetCredentialFromConnectionString(connectionString), + Credential = credential, + AllowInsecureCredentials = credential is null, }; + } /// /// Creates a gRPC channel for communicating with the Durable Task Scheduler service. diff --git a/src/Worker/Grpc/GrpcDurableTaskWorker.cs b/src/Worker/Grpc/GrpcDurableTaskWorker.cs index d685a4fe1..cb11054d1 100644 --- a/src/Worker/Grpc/GrpcDurableTaskWorker.cs +++ b/src/Worker/Grpc/GrpcDurableTaskWorker.cs @@ -46,8 +46,8 @@ public GrpcDurableTaskWorker( /// protected override async Task ExecuteAsync(CancellationToken stoppingToken) { - await using AsyncDisposable disposable = this.GetCallInvoker(out CallInvoker callInvoker); - this.logger.StartingTaskHubWorker(); + await using AsyncDisposable disposable = this.GetCallInvoker(out CallInvoker callInvoker, out string address); + this.logger.StartingTaskHubWorker(address); await new Processor(this, new(callInvoker)).ExecuteAsync(stoppingToken); } @@ -75,22 +75,25 @@ static GrpcChannel GetChannel(string? address) } #endif - AsyncDisposable GetCallInvoker(out CallInvoker callInvoker) + AsyncDisposable GetCallInvoker(out CallInvoker callInvoker, out string address) { if (this.grpcOptions.Channel is GrpcChannel c) { callInvoker = c.CreateCallInvoker(); + address = c.Target; return default; } if (this.grpcOptions.CallInvoker is CallInvoker invoker) { callInvoker = invoker; + address = "(unspecified)"; return default; } c = GetChannel(this.grpcOptions.Address); callInvoker = c.CreateCallInvoker(); + address = c.Target; return new AsyncDisposable(() => new(c.ShutdownAsync())); } } diff --git a/src/Worker/Grpc/Logs.cs b/src/Worker/Grpc/Logs.cs index d6c978fe3..2ff8d40ec 100644 --- a/src/Worker/Grpc/Logs.cs +++ b/src/Worker/Grpc/Logs.cs @@ -13,8 +13,8 @@ namespace Microsoft.DurableTask.Worker.Grpc /// static partial class Logs { - [LoggerMessage(EventId = 1, Level = LogLevel.Information, Message = "Durable Task gRPC worker starting.")] - public static partial void StartingTaskHubWorker(this ILogger logger); + [LoggerMessage(EventId = 1, Level = LogLevel.Information, Message = "Durable Task gRPC worker starting and connecting to {endpoint}.")] + public static partial void StartingTaskHubWorker(this ILogger logger, string endpoint); [LoggerMessage(EventId = 2, Level = LogLevel.Information, Message = "Durable Task gRPC worker has disconnected from gRPC server.")] public static partial void SidecarDisconnected(this ILogger logger); diff --git a/test/Client/AzureManaged.Tests/DurableTaskSchedulerClientExtensionsTests.cs b/test/Client/AzureManaged.Tests/DurableTaskSchedulerClientExtensionsTests.cs index 599fa1c7b..d625703ca 100644 --- a/test/Client/AzureManaged.Tests/DurableTaskSchedulerClientExtensionsTests.cs +++ b/test/Client/AzureManaged.Tests/DurableTaskSchedulerClientExtensionsTests.cs @@ -65,6 +65,32 @@ public void UseDurableTaskScheduler_WithConnectionString_ShouldConfigureCorrectl clientOptions.Credential.Should().BeOfType(); } + [Fact] + public void UseDurableTaskScheduler_WithLocalhostConnectionString_ShouldConfigureCorrectly() + { + // Arrange + ServiceCollection services = new(); + Mock mockBuilder = new(); + mockBuilder.Setup(b => b.Services).Returns(services); + string connectionString = $"Endpoint=http://localhost;Authentication=None;TaskHub={ValidTaskHub}"; + + // Act + mockBuilder.Object.UseDurableTaskScheduler(connectionString); + + // Assert + ServiceProvider provider = services.BuildServiceProvider(); + IOptions? options = provider.GetService>(); + options.Should().NotBeNull(); + + // Validate the configured options + var workerOptions = provider.GetRequiredService>().Value; + workerOptions.EndpointAddress.Should().Be("http://localhost"); + workerOptions.TaskHubName.Should().Be(ValidTaskHub); + workerOptions.Credential.Should().BeNull(); + workerOptions.ResourceId.Should().Be("https://durabletask.io"); + workerOptions.AllowInsecureCredentials.Should().BeTrue(); + } + [Theory] [InlineData(null, "testhub")] [InlineData("myaccount.westus3.durabletask.io", null)] @@ -124,7 +150,7 @@ public void UseDurableTaskScheduler_WithInvalidConnectionString_ShouldThrowArgum // Assert action.Should().Throw() - .WithMessage("Value cannot be null. (Parameter 'Endpoint')"); + .WithMessage("Value cannot be null. (Parameter '*')"); } [Theory] diff --git a/test/Worker/AzureManaged.Tests/DurableTaskSchedulerWorkerExtensionsTests.cs b/test/Worker/AzureManaged.Tests/DurableTaskSchedulerWorkerExtensionsTests.cs index bec5a962a..49e8df4e3 100644 --- a/test/Worker/AzureManaged.Tests/DurableTaskSchedulerWorkerExtensionsTests.cs +++ b/test/Worker/AzureManaged.Tests/DurableTaskSchedulerWorkerExtensionsTests.cs @@ -69,6 +69,32 @@ public void UseDurableTaskScheduler_WithConnectionString_ShouldConfigureCorrectl workerOptions.AllowInsecureCredentials.Should().BeFalse(); } + [Fact] + public void UseDurableTaskScheduler_WithLocalhostConnectionString_ShouldConfigureCorrectly() + { + // Arrange + ServiceCollection services = new(); + Mock mockBuilder = new(); + mockBuilder.Setup(b => b.Services).Returns(services); + string connectionString = $"Endpoint=http://localhost;Authentication=None;TaskHub={ValidTaskHub}"; + + // Act + mockBuilder.Object.UseDurableTaskScheduler(connectionString); + + // Assert + ServiceProvider provider = services.BuildServiceProvider(); + IOptions? options = provider.GetService>(); + options.Should().NotBeNull(); + + // Validate the configured options + var workerOptions = provider.GetRequiredService>().Value; + workerOptions.EndpointAddress.Should().Be("http://localhost"); + workerOptions.TaskHubName.Should().Be(ValidTaskHub); + workerOptions.Credential.Should().BeNull(); + workerOptions.ResourceId.Should().Be("https://durabletask.io"); + workerOptions.AllowInsecureCredentials.Should().BeTrue(); + } + [Theory] [InlineData(null, "testhub")] [InlineData("myaccount.westus3.durabletask.io", null)] @@ -129,7 +155,7 @@ public void UseDurableTaskScheduler_WithInvalidConnectionString_ShouldThrowArgum // Assert action.Should().Throw() - .WithMessage("Value cannot be null. (Parameter 'Endpoint')"); + .WithMessage("Value cannot be null. (Parameter '*')"); } [Theory]