From 96b4dc50436326d1312b5ee85c48a11bd7b7a062 Mon Sep 17 00:00:00 2001 From: peterstone2017 <12449837+YunchuWang@users.noreply.github.com> Date: Thu, 26 Feb 2026 20:30:46 -0800 Subject: [PATCH 1/5] Fix build warnings and clean up exception message - Remove duplicate BenchmarkDotNet 0.14.0 entry in Directory.Packages.props (fixes NU1506) - Upgrade ExportHistoryWebApp from net6.0 to net8.0 (fixes NETSDK1138) - Remove 'TODO' prefix from exception message in TaskHubGrpcServer --- Directory.Packages.props | 1 - samples/ExportHistoryWebApp/ExportHistoryWebApp.csproj | 2 +- src/InProcessTestHost/Sidecar/Grpc/TaskHubGrpcServer.cs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 76c4dd51d..aff8b6de0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -65,7 +65,6 @@ - diff --git a/samples/ExportHistoryWebApp/ExportHistoryWebApp.csproj b/samples/ExportHistoryWebApp/ExportHistoryWebApp.csproj index 884da7e8b..6c63020af 100644 --- a/samples/ExportHistoryWebApp/ExportHistoryWebApp.csproj +++ b/samples/ExportHistoryWebApp/ExportHistoryWebApp.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 enable enable true diff --git a/src/InProcessTestHost/Sidecar/Grpc/TaskHubGrpcServer.cs b/src/InProcessTestHost/Sidecar/Grpc/TaskHubGrpcServer.cs index 43603ffac..50f1fe155 100644 --- a/src/InProcessTestHost/Sidecar/Grpc/TaskHubGrpcServer.cs +++ b/src/InProcessTestHost/Sidecar/Grpc/TaskHubGrpcServer.cs @@ -902,7 +902,7 @@ async Task SendWorkItemToClientAsync(P.WorkItem workItem) { outputStream = this.workerToClientStream ?? // CA2201: Use specific exception types - throw new InvalidOperationException("TODO: No client is connected! Need to wait until a client connects before executing!"); + throw new InvalidOperationException("No client is connected. Need to wait until a client connects before executing."); } // The gRPC channel can only handle one message at a time, so we need to serialize access to it. From c8ff3f57e67d09e5599db2db76abfa2574ecdccd Mon Sep 17 00:00:00 2001 From: peterstone2017 <12449837+YunchuWang@users.noreply.github.com> Date: Fri, 27 Feb 2026 09:07:59 -0800 Subject: [PATCH 2/5] Add logging to GrpcDurableEntityClient and ExecuteScheduleOperationOrchestrator - Add LoggerMessage methods for entity client operations (SignalingEntity, GettingEntity, QueryingEntities, CleaningEntityStorage) in Logs.cs - Wire logging calls into GrpcDurableEntityClient replacing TODO comment - Add replay-safe logging to ExecuteScheduleOperationOrchestrator with operation start/complete/error messages - Update orchestrator tests to mock CreateReplaySafeLogger --- src/Client/Grpc/GrpcDurableEntityClient.cs | 11 +++++++---- src/Client/Grpc/Logs.cs | 12 ++++++++++++ .../ExecuteScheduleOperationOrchestrator.cs | 19 +++++++++++++++++-- ...ecuteScheduleOperationOrchestratorTests.cs | 5 +++++ 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/Client/Grpc/GrpcDurableEntityClient.cs b/src/Client/Grpc/GrpcDurableEntityClient.cs index fd8e63926..a12665eaf 100644 --- a/src/Client/Grpc/GrpcDurableEntityClient.cs +++ b/src/Client/Grpc/GrpcDurableEntityClient.cs @@ -55,10 +55,10 @@ public override async Task SignalEntityAsync( RequestId = requestId.ToString(), Name = operationName, Input = this.dataConverter.Serialize(input), - ScheduledTime = scheduledTime?.ToTimestamp(), + ScheduledTime = scheduledTime?.ToTimestamp(), RequestTime = DateTimeOffset.UtcNow.ToTimestamp(), - }; - + }; + if (Activity.Current is { } activity) { request.ParentTraceContext ??= new P.TraceContext(); @@ -66,7 +66,7 @@ public override async Task SignalEntityAsync( request.ParentTraceContext.TraceState = activity.TraceStateString; } - // TODO this.logger.LogSomething + this.logger.SignalingEntity(id.ToString(), operationName); try { await this.sidecarClient.SignalEntityAsync(request, cancellationToken: cancellation); @@ -107,6 +107,7 @@ public override async Task CleanEntityStorageAsync( int emptyEntitiesRemoved = 0; int orphanedLocksReleased = 0; + this.logger.CleaningEntityStorage(); try { do @@ -156,6 +157,7 @@ public override async Task CleanEntityStorageAsync( IncludeState = includeState, }; + this.logger.GettingEntity(id.ToString()); try { P.GetEntityResponse response = await this.sidecarClient @@ -180,6 +182,7 @@ AsyncPageable GetAllEntitiesCoreAsync( DateTimeOffset? lastModifiedFrom = filter?.LastModifiedFrom; DateTimeOffset? lastModifiedTo = filter?.LastModifiedTo; + this.logger.QueryingEntities(startsWith, lastModifiedFrom, lastModifiedTo); return Pageable.Create(async (continuation, pageSize, cancellation) => { pageSize ??= filter?.PageSize; diff --git a/src/Client/Grpc/Logs.cs b/src/Client/Grpc/Logs.cs index 8887f17d9..3b73dae8b 100644 --- a/src/Client/Grpc/Logs.cs +++ b/src/Client/Grpc/Logs.cs @@ -49,5 +49,17 @@ public static void PurgingInstances(this ILogger logger, PurgeInstancesFilter fi string? statuses = filter?.Statuses is null ? null : string.Join("|", filter.Statuses); PurgingInstances(logger, filter?.CreatedFrom, filter?.CreatedTo, statuses); } + + [LoggerMessage(EventId = 47, Level = LogLevel.Information, Message = "Signaling entity '{instanceId}' with operation '{operationName}'.")] + public static partial void SignalingEntity(this ILogger logger, string instanceId, string operationName); + + [LoggerMessage(EventId = 48, Level = LogLevel.Information, Message = "Getting entity '{instanceId}'.")] + public static partial void GettingEntity(this ILogger logger, string instanceId); + + [LoggerMessage(EventId = 50, Level = LogLevel.Information, Message = "Querying entities with filter: {{ StartsWith = {startsWith}, LastModifiedFrom = {lastModifiedFrom}, LastModifiedTo = {lastModifiedTo} }}")] + public static partial void QueryingEntities(this ILogger logger, string? startsWith, DateTimeOffset? lastModifiedFrom, DateTimeOffset? lastModifiedTo); + + [LoggerMessage(EventId = 52, Level = LogLevel.Information, Message = "Cleaning entity storage.")] + public static partial void CleaningEntityStorage(this ILogger logger); } } diff --git a/src/ScheduledTasks/Orchestrations/ExecuteScheduleOperationOrchestrator.cs b/src/ScheduledTasks/Orchestrations/ExecuteScheduleOperationOrchestrator.cs index 0f2baa0b2..d587cdcaa 100644 --- a/src/ScheduledTasks/Orchestrations/ExecuteScheduleOperationOrchestrator.cs +++ b/src/ScheduledTasks/Orchestrations/ExecuteScheduleOperationOrchestrator.cs @@ -2,10 +2,10 @@ // Licensed under the MIT License. using Microsoft.DurableTask.Entities; +using Microsoft.Extensions.Logging; namespace Microsoft.DurableTask.ScheduledTasks; -// TODO: logging // TODO: May need separate orchs, result is obj now /// @@ -18,7 +18,22 @@ public class ExecuteScheduleOperationOrchestrator : TaskOrchestrator public override async Task RunAsync(TaskOrchestrationContext context, ScheduleOperationRequest input) { - return await context.Entities.CallEntityAsync(input.EntityId, input.OperationName, input.Input); + ILogger logger = context.CreateReplaySafeLogger(); + string scheduleId = input.EntityId.Key; + + logger.ScheduleOperationInfo(scheduleId, input.OperationName, "Executing schedule operation via orchestrator"); + + try + { + object result = await context.Entities.CallEntityAsync(input.EntityId, input.OperationName, input.Input); + logger.ScheduleOperationInfo(scheduleId, input.OperationName, "Schedule operation completed successfully"); + return result; + } + catch (Exception ex) + { + logger.ScheduleOperationError(scheduleId, input.OperationName, ex.Message, ex); + throw; + } } } diff --git a/test/ScheduledTasks.Tests/Orchestrations/ExecuteScheduleOperationOrchestratorTests.cs b/test/ScheduledTasks.Tests/Orchestrations/ExecuteScheduleOperationOrchestratorTests.cs index 89b6024d3..1c2ab56de 100644 --- a/test/ScheduledTasks.Tests/Orchestrations/ExecuteScheduleOperationOrchestratorTests.cs +++ b/test/ScheduledTasks.Tests/Orchestrations/ExecuteScheduleOperationOrchestratorTests.cs @@ -4,6 +4,8 @@ using Microsoft.DurableTask.Client; using Microsoft.DurableTask.Client.Entities; using Microsoft.DurableTask.Entities; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using Xunit; @@ -20,6 +22,9 @@ public ExecuteScheduleOperationOrchestratorTests() this.mockContext = new Mock(MockBehavior.Strict); this.mockEntityClient = new Mock(MockBehavior.Loose); this.mockContext.Setup(c => c.Entities).Returns(this.mockEntityClient.Object); + this.mockContext + .Setup(c => c.CreateReplaySafeLogger()) + .Returns(NullLogger.Instance); this.orchestrator = new ExecuteScheduleOperationOrchestrator(); } From db37bf4e427f3ecd1dc33f0e507e3d8b2d423cf7 Mon Sep 17 00:00:00 2001 From: wangbill Date: Fri, 27 Feb 2026 10:13:46 -0800 Subject: [PATCH 3/5] Update src/ScheduledTasks/Orchestrations/ExecuteScheduleOperationOrchestrator.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Orchestrations/ExecuteScheduleOperationOrchestrator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScheduledTasks/Orchestrations/ExecuteScheduleOperationOrchestrator.cs b/src/ScheduledTasks/Orchestrations/ExecuteScheduleOperationOrchestrator.cs index d587cdcaa..b601f9560 100644 --- a/src/ScheduledTasks/Orchestrations/ExecuteScheduleOperationOrchestrator.cs +++ b/src/ScheduledTasks/Orchestrations/ExecuteScheduleOperationOrchestrator.cs @@ -31,7 +31,7 @@ public override async Task RunAsync(TaskOrchestrationContext context, Sc } catch (Exception ex) { - logger.ScheduleOperationError(scheduleId, input.OperationName, ex.Message, ex); + logger.ScheduleOperationError(scheduleId, input.OperationName, "Failed to execute schedule operation via orchestrator", ex); throw; } } From 126a1860d6beca68d846ecab9e0b667ded6eaa2e Mon Sep 17 00:00:00 2001 From: wangbill Date: Fri, 27 Feb 2026 10:21:38 -0800 Subject: [PATCH 4/5] Update test/ScheduledTasks.Tests/Orchestrations/ExecuteScheduleOperationOrchestratorTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Orchestrations/ExecuteScheduleOperationOrchestratorTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/ScheduledTasks.Tests/Orchestrations/ExecuteScheduleOperationOrchestratorTests.cs b/test/ScheduledTasks.Tests/Orchestrations/ExecuteScheduleOperationOrchestratorTests.cs index 1c2ab56de..914c7650f 100644 --- a/test/ScheduledTasks.Tests/Orchestrations/ExecuteScheduleOperationOrchestratorTests.cs +++ b/test/ScheduledTasks.Tests/Orchestrations/ExecuteScheduleOperationOrchestratorTests.cs @@ -4,7 +4,6 @@ using Microsoft.DurableTask.Client; using Microsoft.DurableTask.Client.Entities; using Microsoft.DurableTask.Entities; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Moq; using Xunit; From eb9211b368119de5eefa34bdaea6fefe6c2a33d8 Mon Sep 17 00:00:00 2001 From: peterstone2017 <12449837+YunchuWang@users.noreply.github.com> Date: Fri, 27 Feb 2026 10:41:12 -0800 Subject: [PATCH 5/5] update --- src/Client/Grpc/Logs.cs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Client/Grpc/Logs.cs b/src/Client/Grpc/Logs.cs index 3b73dae8b..2a8594e07 100644 --- a/src/Client/Grpc/Logs.cs +++ b/src/Client/Grpc/Logs.cs @@ -39,6 +39,18 @@ static partial class Logs [LoggerMessage(EventId = 46, Level = LogLevel.Information, Message = "Purging instances with filter: {{ CreatedFrom = {createdFrom}, CreatedTo = {createdTo}, Statuses = {statuses} }}")] public static partial void PurgingInstances(this ILogger logger, DateTimeOffset? createdFrom, DateTimeOffset? createdTo, string? statuses); + [LoggerMessage(EventId = 47, Level = LogLevel.Information, Message = "Signaling entity '{instanceId}' with operation '{operationName}'.")] + public static partial void SignalingEntity(this ILogger logger, string instanceId, string operationName); + + [LoggerMessage(EventId = 48, Level = LogLevel.Information, Message = "Getting entity '{instanceId}'.")] + public static partial void GettingEntity(this ILogger logger, string instanceId); + + [LoggerMessage(EventId = 49, Level = LogLevel.Information, Message = "Querying entities with filter: {{ StartsWith = {startsWith}, LastModifiedFrom = {lastModifiedFrom}, LastModifiedTo = {lastModifiedTo} }}")] + public static partial void QueryingEntities(this ILogger logger, string? startsWith, DateTimeOffset? lastModifiedFrom, DateTimeOffset? lastModifiedTo); + + [LoggerMessage(EventId = 50, Level = LogLevel.Information, Message = "Cleaning entity storage.")] + public static partial void CleaningEntityStorage(this ILogger logger); + /// /// . /// @@ -49,17 +61,5 @@ public static void PurgingInstances(this ILogger logger, PurgeInstancesFilter fi string? statuses = filter?.Statuses is null ? null : string.Join("|", filter.Statuses); PurgingInstances(logger, filter?.CreatedFrom, filter?.CreatedTo, statuses); } - - [LoggerMessage(EventId = 47, Level = LogLevel.Information, Message = "Signaling entity '{instanceId}' with operation '{operationName}'.")] - public static partial void SignalingEntity(this ILogger logger, string instanceId, string operationName); - - [LoggerMessage(EventId = 48, Level = LogLevel.Information, Message = "Getting entity '{instanceId}'.")] - public static partial void GettingEntity(this ILogger logger, string instanceId); - - [LoggerMessage(EventId = 50, Level = LogLevel.Information, Message = "Querying entities with filter: {{ StartsWith = {startsWith}, LastModifiedFrom = {lastModifiedFrom}, LastModifiedTo = {lastModifiedTo} }}")] - public static partial void QueryingEntities(this ILogger logger, string? startsWith, DateTimeOffset? lastModifiedFrom, DateTimeOffset? lastModifiedTo); - - [LoggerMessage(EventId = 52, Level = LogLevel.Information, Message = "Cleaning entity storage.")] - public static partial void CleaningEntityStorage(this ILogger logger); } }