From 405010f805b9edf13d00c245ddfe03336fa0e2c2 Mon Sep 17 00:00:00 2001 From: Sophia Tevosyan Date: Fri, 11 Jul 2025 13:06:58 -0700 Subject: [PATCH 1/4] first commit --- .../EntityTriggerAttributeBindingProvider.cs | 2 +- .../RemoteEntityContext.cs | 16 +++++++++--- .../OutOfProcMiddleware.cs | 11 +++++--- .../ProtobufUtils.cs | 6 +++-- .../RemoteEntityConfiguration.cs | 26 +++++++++++++++++++ .../DurableTaskFunctionsMiddleware.cs | 11 +++++--- ...tionsWorkerApplicationBuilderExtensions.cs | 6 ++++- .../TaskEntityDispatcher.cs | 7 +++-- 8 files changed, 69 insertions(+), 16 deletions(-) create mode 100644 src/WebJobs.Extensions.DurableTask/RemoteEntityConfiguration.cs diff --git a/src/WebJobs.Extensions.DurableTask/Bindings/EntityTriggerAttributeBindingProvider.cs b/src/WebJobs.Extensions.DurableTask/Bindings/EntityTriggerAttributeBindingProvider.cs index 91e6d6a64..92fd1ed5b 100644 --- a/src/WebJobs.Extensions.DurableTask/Bindings/EntityTriggerAttributeBindingProvider.cs +++ b/src/WebJobs.Extensions.DurableTask/Bindings/EntityTriggerAttributeBindingProvider.cs @@ -130,7 +130,7 @@ public Task BindAsync(object value, ValueBindingContext context) { // Generate a byte array which is the serialized protobuf payload // https://developers.google.com/protocol-buffers/docs/csharptutorial#parsing_and_serialization - var entityBatchRequest = remoteContext.Request.ToEntityBatchRequest(); + var entityBatchRequest = remoteContext.Request.ToEntityBatchRequest(remoteContext.Configurations); // We convert the binary payload into a base64 string because that seems to be the most commonly supported // format for Azure Functions language workers. Attempts to send unencoded byte[] payloads were unsuccessful. diff --git a/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteEntityContext.cs b/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteEntityContext.cs index c2bf96369..682dc6291 100644 --- a/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteEntityContext.cs +++ b/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteEntityContext.cs @@ -5,19 +5,29 @@ using System.Collections.Generic; using DurableTask.Core.Entities; using DurableTask.Core.Entities.OperationFormat; +using Microsoft.Extensions.Options; using Newtonsoft.Json; namespace Microsoft.Azure.WebJobs.Extensions.DurableTask { internal class RemoteEntityContext { - public RemoteEntityContext(EntityBatchRequest batchRequest) + public RemoteEntityContext(EntityBatchRequest batchRequest, DurableTaskOptions options, bool extendedSession, bool includeEntityState) { - this.Request = batchRequest; + this.Request = batchRequest; + this.Configurations = new RemoteEntityConfiguration + { + ExtendedSession = extendedSession, + IncludeEntityState = includeEntityState, + ExtendedSessionIdleTimeoutInSeconds = options.ExtendedSessionIdleTimeoutInSeconds, + }; } [JsonProperty("request")] - internal EntityBatchRequest Request { get; private set; } + internal EntityBatchRequest Request { get; private set; } + + [JsonProperty("configurations")] + public RemoteEntityConfiguration Configurations { get; private set; } [JsonIgnore] internal EntityBatchResult? Result { get; set; } diff --git a/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs b/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs index f0898aa3a..434b0a917 100644 --- a/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs +++ b/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs @@ -339,9 +339,14 @@ void SetErrorResult(FailureDetails failureDetails) batchRequest.InstanceId, batchRequest.EntityState, functionType: FunctionType.Entity, - isReplay: false); - - var context = new RemoteEntityContext(batchRequest); + isReplay: false); + + bool extendedSession = dispatchContext.GetProperty("extendedSession"); + bool includeEntityState = dispatchContext.GetProperty("includeEntityState"); + + // The extendedSession property will be ignored if the middleware does not support extended sessions, but it is important to only set includeEntityState to false if extended sessions are enabled. + // Otherwise the entity state will not be added to the EntityBatchRequest by the EntityTriggerAttributeBindingProvider, even if the middleware does not support extended sessions and needs the entity's state. + var context = new RemoteEntityContext(batchRequest, this.Options, extendedSession, !this.Options.ExtendedSessionsEnabled || includeEntityState); var input = new TriggeredFunctionData { diff --git a/src/WebJobs.Extensions.DurableTask/ProtobufUtils.cs b/src/WebJobs.Extensions.DurableTask/ProtobufUtils.cs index 49ef2932b..8ca49a1f6 100644 --- a/src/WebJobs.Extensions.DurableTask/ProtobufUtils.cs +++ b/src/WebJobs.Extensions.DurableTask/ProtobufUtils.cs @@ -463,7 +463,7 @@ internal static P.PurgeInstancesResponse CreatePurgeInstancesResponse(PurgeResul /// The operation request to convert. /// The converted operation request. [return: NotNullIfNotNull("entityBatchRequest")] - internal static P.EntityBatchRequest? ToEntityBatchRequest(this EntityBatchRequest? entityBatchRequest) + internal static P.EntityBatchRequest? ToEntityBatchRequest(this EntityBatchRequest? entityBatchRequest, RemoteEntityConfiguration configurations) { if (entityBatchRequest == null) { @@ -473,9 +473,11 @@ internal static P.PurgeInstancesResponse CreatePurgeInstancesResponse(PurgeResul var batchRequest = new P.EntityBatchRequest() { InstanceId = entityBatchRequest.InstanceId, - EntityState = entityBatchRequest.EntityState, + EntityState = configurations.IncludeEntityState ? entityBatchRequest.EntityState : null, }; + batchRequest.Properties.Add(ProtobufUtils.ConvertPocoToProtoMap(configurations)); + foreach (var operation in entityBatchRequest.Operations ?? Enumerable.Empty()) { batchRequest.Operations.Add(operation.ToOperationRequest()); diff --git a/src/WebJobs.Extensions.DurableTask/RemoteEntityConfiguration.cs b/src/WebJobs.Extensions.DurableTask/RemoteEntityConfiguration.cs new file mode 100644 index 000000000..e5198c454 --- /dev/null +++ b/src/WebJobs.Extensions.DurableTask/RemoteEntityConfiguration.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Azure.WebJobs.Extensions.DurableTask +{ + /// + /// Configuration settings for RemoteEntityContext in out-of-process mode, transmitted via gRPC. + /// + public class RemoteEntityConfiguration + { + /// + /// Gets or sets whether or not to include the entity state in the entity batch request. + /// + public bool IncludeEntityState { get; set; } = true; + + /// + /// Gets or sets whether or not the entity batch request is within an extended session. + /// + public bool ExtendedSession { get; set; } = false; + + /// + /// Gets or sets the amount of time in seconds before an idle extended session times out. + /// + public int ExtendedSessionIdleTimeoutInSeconds { get; set; } + } +} diff --git a/src/Worker.Extensions.DurableTask/DurableTaskFunctionsMiddleware.cs b/src/Worker.Extensions.DurableTask/DurableTaskFunctionsMiddleware.cs index be1919673..264122dd3 100644 --- a/src/Worker.Extensions.DurableTask/DurableTaskFunctionsMiddleware.cs +++ b/src/Worker.Extensions.DurableTask/DurableTaskFunctionsMiddleware.cs @@ -7,14 +7,17 @@ using Microsoft.Azure.Functions.Worker.Extensions.DurableTask.Exceptions; using Microsoft.Azure.Functions.Worker.Middleware; using Microsoft.DurableTask.Worker.Grpc; +using Microsoft.Extensions.Caching.Memory; namespace Microsoft.Azure.Functions.Worker.Extensions.DurableTask; /// /// A middleware to handle orchestration triggers. /// -internal class DurableTaskFunctionsMiddleware : IFunctionsWorkerMiddleware +internal class DurableTaskFunctionsMiddleware(IMemoryCache extendedSessions) : IFunctionsWorkerMiddleware { + private readonly IMemoryCache extendedSessions = extendedSessions; + /// public Task Invoke(FunctionContext functionContext, FunctionExecutionDelegate next) { @@ -25,7 +28,7 @@ public Task Invoke(FunctionContext functionContext, FunctionExecutionDelegate ne if (IsEntityTrigger(functionContext, out triggerBinding)) { - return RunEntityAsync(functionContext, triggerBinding, next); + return this.RunEntityAsync(functionContext, triggerBinding, next); } if (IsActivityTrigger(functionContext, out triggerBinding)) @@ -85,7 +88,7 @@ private static bool IsEntityTrigger( return false; } - static async Task RunEntityAsync( + async Task RunEntityAsync( FunctionContext context, BindingMetadata triggerBinding, FunctionExecutionDelegate next) { InputBindingData triggerInputData = await context.BindInputAsync(triggerBinding); @@ -94,7 +97,7 @@ static async Task RunEntityAsync( throw new InvalidOperationException("Entity batch was either missing from the input or not a string value."); } - TaskEntityDispatcher dispatcher = new(encodedEntityBatch, context.InstanceServices); + TaskEntityDispatcher dispatcher = new(encodedEntityBatch, context.InstanceServices, this.extendedSessions); triggerInputData.Value = dispatcher; await next(context); diff --git a/src/Worker.Extensions.DurableTask/FunctionsWorkerApplicationBuilderExtensions.cs b/src/Worker.Extensions.DurableTask/FunctionsWorkerApplicationBuilderExtensions.cs index 642446dd4..ca404f33e 100644 --- a/src/Worker.Extensions.DurableTask/FunctionsWorkerApplicationBuilderExtensions.cs +++ b/src/Worker.Extensions.DurableTask/FunctionsWorkerApplicationBuilderExtensions.cs @@ -58,7 +58,11 @@ public static IFunctionsWorkerApplicationBuilder ConfigureDurableExtension(this if (!builder.Services.Any(d => d.ServiceType == typeof(DurableTaskFunctionsMiddleware))) { builder.UseMiddleware(); - } + } + builder.Services.AddMemoryCache(options => + { + options.ExpirationScanFrequency = TimeSpan.FromSeconds(5); + }); return builder; } diff --git a/src/Worker.Extensions.DurableTask/TaskEntityDispatcher.cs b/src/Worker.Extensions.DurableTask/TaskEntityDispatcher.cs index 952de32b2..a43450e18 100644 --- a/src/Worker.Extensions.DurableTask/TaskEntityDispatcher.cs +++ b/src/Worker.Extensions.DurableTask/TaskEntityDispatcher.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Microsoft.DurableTask.Entities; using Microsoft.DurableTask.Worker.Grpc; +using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; namespace Microsoft.Azure.Functions.Worker; @@ -19,11 +20,13 @@ public sealed class TaskEntityDispatcher { private readonly string request; private readonly IServiceProvider services; + private readonly IMemoryCache entityStates; - internal TaskEntityDispatcher(string request, IServiceProvider services) + internal TaskEntityDispatcher(string request, IServiceProvider services, IMemoryCache entityStates) { this.request = request; this.services = services; + this.entityStates = entityStates; } internal string Result { get; private set; } = string.Empty; @@ -40,7 +43,7 @@ public async Task DispatchAsync(ITaskEntity entity) throw new ArgumentNullException(nameof(entity)); } - this.Result = await GrpcEntityRunner.LoadAndRunAsync(this.request, entity, this.services); + this.Result = await GrpcEntityRunner.LoadAndRunAsync(this.request, entity, this.entityStates, this.services); } /// From ca6ad2e11fca4ea01bfc152c33b55636d086672e Mon Sep 17 00:00:00 2001 From: Sophia Tevosyan Date: Thu, 13 Nov 2025 16:47:17 -0800 Subject: [PATCH 2/4] updating implementation to match orchestration one --- .../RemoteEntityContext.cs | 15 +++++++++------ .../OutOfProcMiddleware.cs | 18 ++++++++++++------ .../ProtobufUtils.cs | 4 ++-- .../DurableFunctionExecutor.Entity.cs | 2 +- ...ctionsWorkerApplicationBuilderExtensions.cs | 6 +----- .../TaskEntityDispatcher.cs | 9 +++++---- 6 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteEntityContext.cs b/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteEntityContext.cs index 682dc6291..54c424994 100644 --- a/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteEntityContext.cs +++ b/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteEntityContext.cs @@ -15,19 +15,22 @@ internal class RemoteEntityContext public RemoteEntityContext(EntityBatchRequest batchRequest, DurableTaskOptions options, bool extendedSession, bool includeEntityState) { this.Request = batchRequest; - this.Configurations = new RemoteEntityConfiguration + if (options.ExtendedSessionsEnabled) { - ExtendedSession = extendedSession, - IncludeEntityState = includeEntityState, - ExtendedSessionIdleTimeoutInSeconds = options.ExtendedSessionIdleTimeoutInSeconds, - }; + this.Configurations = new RemoteEntityConfiguration + { + ExtendedSession = extendedSession, + IncludeEntityState = includeEntityState, + ExtendedSessionIdleTimeoutInSeconds = options.ExtendedSessionIdleTimeoutInSeconds, + }; + } } [JsonProperty("request")] internal EntityBatchRequest Request { get; private set; } [JsonProperty("configurations")] - public RemoteEntityConfiguration Configurations { get; private set; } + public RemoteEntityConfiguration? Configurations { get; private set; } [JsonIgnore] internal EntityBatchResult? Result { get; set; } diff --git a/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs b/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs index 934ee6942..30f168fad 100644 --- a/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs +++ b/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs @@ -114,7 +114,7 @@ await this.LifeCycleNotificationHelper.OrchestratorStartingAsync( bool isExtendedSession = workItemMetadata.IsExtendedSession; bool includePastEvents = workItemMetadata.IncludePastEvents; - var context = new RemoteOrchestratorContext(runtimeState, entityParameters, this.extension.Options, isExtendedSession, includePastEvents); + var context = new RemoteOrchestratorContext(runtimeState, entityParameters, this.Options, isExtendedSession, includePastEvents); bool workerRequiresHistory = false; var input = new TriggeredFunctionData @@ -353,12 +353,12 @@ void SetErrorResult(FailureDetails failureDetails) functionType: FunctionType.Entity, isReplay: false); - bool extendedSession = dispatchContext.GetProperty("extendedSession"); - bool includeEntityState = dispatchContext.GetProperty("includeEntityState"); + WorkItemMetadata workItemMetadata = dispatchContext.GetProperty(); + bool isExtendedSession = workItemMetadata.IsExtendedSession; + bool includeEntityState = workItemMetadata.IncludePastEvents; - // The extendedSession property will be ignored if the middleware does not support extended sessions, but it is important to only set includeEntityState to false if extended sessions are enabled. - // Otherwise the entity state will not be added to the EntityBatchRequest by the EntityTriggerAttributeBindingProvider, even if the middleware does not support extended sessions and needs the entity's state. - var context = new RemoteEntityContext(batchRequest, this.Options, extendedSession, !this.Options.ExtendedSessionsEnabled || includeEntityState); + var context = new RemoteEntityContext(batchRequest, this.Options, isExtendedSession, includeEntityState); + bool workerRequiresEntityState = false; var input = new TriggeredFunctionData { @@ -386,6 +386,7 @@ void SetErrorResult(FailureDetails failureDetails) byte[] triggerReturnValueBytes = Convert.FromBase64String(triggerReturnValue); P.EntityBatchResult response = P.EntityBatchResult.Parser.ParseFrom(triggerReturnValueBytes); + workerRequiresEntityState = response.RequiresState; context.Result = response.ToEntityBatchResult(); context.ThrowIfFailed(); @@ -454,6 +455,11 @@ void SetErrorResult(FailureDetails failureDetails) } return; + } + + if (workerRequiresEntityState) + { + throw new SessionAbortedException("The worker has since ended the extended session and needs an entity state to execute the request."); } EntityBatchResult batchResult = context.Result diff --git a/src/WebJobs.Extensions.DurableTask/ProtobufUtils.cs b/src/WebJobs.Extensions.DurableTask/ProtobufUtils.cs index 6a786e315..d96d5a0aa 100644 --- a/src/WebJobs.Extensions.DurableTask/ProtobufUtils.cs +++ b/src/WebJobs.Extensions.DurableTask/ProtobufUtils.cs @@ -486,7 +486,7 @@ internal static P.PurgeInstancesResponse CreatePurgeInstancesResponse(PurgeResul /// The operation request to convert. /// The converted operation request. [return: NotNullIfNotNull("entityBatchRequest")] - internal static P.EntityBatchRequest? ToEntityBatchRequest(this EntityBatchRequest? entityBatchRequest, RemoteEntityConfiguration configurations) + internal static P.EntityBatchRequest? ToEntityBatchRequest(this EntityBatchRequest? entityBatchRequest, RemoteEntityConfiguration? configurations) { if (entityBatchRequest == null) { @@ -496,7 +496,7 @@ internal static P.PurgeInstancesResponse CreatePurgeInstancesResponse(PurgeResul var batchRequest = new P.EntityBatchRequest() { InstanceId = entityBatchRequest.InstanceId, - EntityState = configurations.IncludeEntityState ? entityBatchRequest.EntityState : null, + EntityState = configurations?.IncludeEntityState == false ? null : entityBatchRequest.EntityState, }; batchRequest.Properties.Add(ProtobufUtils.ConvertPocoToProtoMap(configurations)); diff --git a/src/Worker.Extensions.DurableTask/Execution/DurableFunctionExecutor.Entity.cs b/src/Worker.Extensions.DurableTask/Execution/DurableFunctionExecutor.Entity.cs index 0e7eaa64b..32e198421 100644 --- a/src/Worker.Extensions.DurableTask/Execution/DurableFunctionExecutor.Entity.cs +++ b/src/Worker.Extensions.DurableTask/Execution/DurableFunctionExecutor.Entity.cs @@ -37,7 +37,7 @@ private async ValueTask RunEntityAsync(FunctionContext context, BindingMetadata return; } - TaskEntityDispatcher dispatcher = new(encodedEntityBatch, context.InstanceServices); + TaskEntityDispatcher dispatcher = new(encodedEntityBatch, context.InstanceServices, extendedSessionsCache); triggerInputData.Value = dispatcher; await inner.ExecuteAsync(context); context.GetInvocationResult().Value = dispatcher.Result; diff --git a/src/Worker.Extensions.DurableTask/FunctionsWorkerApplicationBuilderExtensions.cs b/src/Worker.Extensions.DurableTask/FunctionsWorkerApplicationBuilderExtensions.cs index a2c254e01..23a6cd648 100644 --- a/src/Worker.Extensions.DurableTask/FunctionsWorkerApplicationBuilderExtensions.cs +++ b/src/Worker.Extensions.DurableTask/FunctionsWorkerApplicationBuilderExtensions.cs @@ -57,11 +57,7 @@ public static IFunctionsWorkerApplicationBuilder ConfigureDurableExtension( if (!builder.Services.Any(d => d.ServiceType == typeof(DurableTaskFunctionsMiddleware))) { builder.UseMiddleware(); - } - builder.Services.AddMemoryCache(options => - { - options.ExpirationScanFrequency = TimeSpan.FromSeconds(5); - }); + } builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); diff --git a/src/Worker.Extensions.DurableTask/TaskEntityDispatcher.cs b/src/Worker.Extensions.DurableTask/TaskEntityDispatcher.cs index e8e4ccfc3..abfbaa3aa 100644 --- a/src/Worker.Extensions.DurableTask/TaskEntityDispatcher.cs +++ b/src/Worker.Extensions.DurableTask/TaskEntityDispatcher.cs @@ -4,6 +4,7 @@ using System; using System.Threading.Tasks; using Microsoft.DurableTask.Entities; +using Microsoft.DurableTask.Worker; using Microsoft.DurableTask.Worker.Grpc; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; @@ -20,13 +21,13 @@ public sealed class TaskEntityDispatcher { private readonly string request; private readonly IServiceProvider services; - private readonly IMemoryCache entityStates; + private readonly ExtendedSessionsCache extendedSessionsCache; - internal TaskEntityDispatcher(string request, IServiceProvider services, IMemoryCache entityStates) + internal TaskEntityDispatcher(string request, IServiceProvider services, ExtendedSessionsCache extendedSessionsCache) { this.request = request; this.services = services; - this.entityStates = entityStates; + this.extendedSessionsCache = extendedSessionsCache; } internal string Result { get; private set; } = string.Empty; @@ -43,7 +44,7 @@ public async Task DispatchAsync(ITaskEntity entity) throw new ArgumentNullException(nameof(entity)); } - this.Result = await GrpcEntityRunner.LoadAndRunAsync(this.request, entity, this.entityStates, this.services); + this.Result = await GrpcEntityRunner.LoadAndRunAsync(this.request, entity, this.extendedSessionsCache, this.services); } /// From 391c3a9fa49f5555ed6ce7bb4bb52ef6231f4251 Mon Sep 17 00:00:00 2001 From: Sophia Tevosyan Date: Thu, 13 Nov 2025 23:08:50 -0800 Subject: [PATCH 3/4] refactoring --- ...strationTriggerAttributeBindingProvider.cs | 2 +- .../RemoteEntityContext.cs | 10 +++---- .../RemoteOrchestratorContext.cs | 6 ++--- .../OutOfProcMiddleware.cs | 17 +++++++----- .../ProtobufUtils.cs | 4 +-- .../RemoteEntityConfiguration.cs | 26 ------------------- ...tion.cs => RemoteInstanceConfiguration.cs} | 6 ++--- 7 files changed, 25 insertions(+), 46 deletions(-) delete mode 100644 src/WebJobs.Extensions.DurableTask/RemoteEntityConfiguration.cs rename src/WebJobs.Extensions.DurableTask/{RemoteOrchestratorConfiguration.cs => RemoteInstanceConfiguration.cs} (83%) diff --git a/src/WebJobs.Extensions.DurableTask/Bindings/OrchestrationTriggerAttributeBindingProvider.cs b/src/WebJobs.Extensions.DurableTask/Bindings/OrchestrationTriggerAttributeBindingProvider.cs index f72bce0bf..8263d0499 100644 --- a/src/WebJobs.Extensions.DurableTask/Bindings/OrchestrationTriggerAttributeBindingProvider.cs +++ b/src/WebJobs.Extensions.DurableTask/Bindings/OrchestrationTriggerAttributeBindingProvider.cs @@ -170,7 +170,7 @@ public Task BindAsync(object? value, ValueBindingContext context) var orchestratorRequest = new Microsoft.DurableTask.Protobuf.OrchestratorRequest() { InstanceId = remoteContext.InstanceId, - PastEvents = { remoteContext.Configurations.IncludePastEvents ? remoteContext.PastEvents.Select(ProtobufUtils.ToHistoryEventProto) : Enumerable.Empty() }, + PastEvents = { remoteContext.Configurations.IncludeState ? remoteContext.PastEvents.Select(ProtobufUtils.ToHistoryEventProto) : Enumerable.Empty() }, NewEvents = { remoteContext.NewEvents.Select(ProtobufUtils.ToHistoryEventProto) }, EntityParameters = remoteContext.EntityParameters.ToProtobuf(), }; diff --git a/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteEntityContext.cs b/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteEntityContext.cs index 54c424994..3d7b0e3bf 100644 --- a/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteEntityContext.cs +++ b/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteEntityContext.cs @@ -12,15 +12,15 @@ namespace Microsoft.Azure.WebJobs.Extensions.DurableTask { internal class RemoteEntityContext { - public RemoteEntityContext(EntityBatchRequest batchRequest, DurableTaskOptions options, bool extendedSession, bool includeEntityState) + public RemoteEntityContext(EntityBatchRequest batchRequest, DurableTaskOptions options, bool isExtendedSession, bool includeEntityState) { this.Request = batchRequest; if (options.ExtendedSessionsEnabled) { - this.Configurations = new RemoteEntityConfiguration + this.Configurations = new RemoteInstanceConfiguration { - ExtendedSession = extendedSession, - IncludeEntityState = includeEntityState, + IsExtendedSession = isExtendedSession, + IncludeState = includeEntityState, ExtendedSessionIdleTimeoutInSeconds = options.ExtendedSessionIdleTimeoutInSeconds, }; } @@ -30,7 +30,7 @@ public RemoteEntityContext(EntityBatchRequest batchRequest, DurableTaskOptions o internal EntityBatchRequest Request { get; private set; } [JsonProperty("configurations")] - public RemoteEntityConfiguration? Configurations { get; private set; } + public RemoteInstanceConfiguration? Configurations { get; private set; } [JsonIgnore] internal EntityBatchResult? Result { get; set; } diff --git a/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteOrchestratorContext.cs b/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteOrchestratorContext.cs index 16150bdd8..d54c6ef03 100644 --- a/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteOrchestratorContext.cs +++ b/src/WebJobs.Extensions.DurableTask/ContextImplementations/RemoteOrchestratorContext.cs @@ -26,14 +26,14 @@ public RemoteOrchestratorContext(OrchestrationRuntimeState runtimeState, TaskOrc { this.runtimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState)); this.EntityParameters = entityParameters; - this.Configurations = new RemoteOrchestratorConfiguration + this.Configurations = new RemoteInstanceConfiguration { HttpDefaultAsyncRequestSleepTimeMilliseconds = options.HttpSettings.DefaultAsyncRequestSleepTimeMilliseconds, }; if (options.ExtendedSessionsEnabled) { this.Configurations.IsExtendedSession = isExtendedSession; - this.Configurations.IncludePastEvents = includePastEvents; + this.Configurations.IncludeState = includePastEvents; this.Configurations.ExtendedSessionIdleTimeoutInSeconds = options.ExtendedSessionIdleTimeoutInSeconds; } } @@ -51,7 +51,7 @@ public RemoteOrchestratorContext(OrchestrationRuntimeState runtimeState, TaskOrc internal int UpperSchemaVersion { get; } = 4; [JsonProperty("configurations")] - public RemoteOrchestratorConfiguration Configurations { get; private set; } + public RemoteInstanceConfiguration Configurations { get; private set; } [JsonIgnore] internal bool OrchestratorCompleted { get; private set; } diff --git a/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs b/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs index 30f168fad..cfcd07553 100644 --- a/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs +++ b/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs @@ -111,10 +111,13 @@ await this.LifeCycleNotificationHelper.OrchestratorStartingAsync( } WorkItemMetadata workItemMetadata = dispatchContext.GetProperty(); - bool isExtendedSession = workItemMetadata.IsExtendedSession; - bool includePastEvents = workItemMetadata.IncludePastEvents; + var context = new RemoteOrchestratorContext( + runtimeState, + entityParameters, + this.Options, + workItemMetadata.IsExtendedSession, + workItemMetadata.IncludeState); - var context = new RemoteOrchestratorContext(runtimeState, entityParameters, this.Options, isExtendedSession, includePastEvents); bool workerRequiresHistory = false; var input = new TriggeredFunctionData @@ -354,10 +357,12 @@ void SetErrorResult(FailureDetails failureDetails) isReplay: false); WorkItemMetadata workItemMetadata = dispatchContext.GetProperty(); - bool isExtendedSession = workItemMetadata.IsExtendedSession; - bool includeEntityState = workItemMetadata.IncludePastEvents; + var context = new RemoteEntityContext( + batchRequest, + this.Options, + workItemMetadata.IsExtendedSession, + workItemMetadata.IncludeState); - var context = new RemoteEntityContext(batchRequest, this.Options, isExtendedSession, includeEntityState); bool workerRequiresEntityState = false; var input = new TriggeredFunctionData diff --git a/src/WebJobs.Extensions.DurableTask/ProtobufUtils.cs b/src/WebJobs.Extensions.DurableTask/ProtobufUtils.cs index d96d5a0aa..c28bc8e80 100644 --- a/src/WebJobs.Extensions.DurableTask/ProtobufUtils.cs +++ b/src/WebJobs.Extensions.DurableTask/ProtobufUtils.cs @@ -486,7 +486,7 @@ internal static P.PurgeInstancesResponse CreatePurgeInstancesResponse(PurgeResul /// The operation request to convert. /// The converted operation request. [return: NotNullIfNotNull("entityBatchRequest")] - internal static P.EntityBatchRequest? ToEntityBatchRequest(this EntityBatchRequest? entityBatchRequest, RemoteEntityConfiguration? configurations) + internal static P.EntityBatchRequest? ToEntityBatchRequest(this EntityBatchRequest? entityBatchRequest, RemoteInstanceConfiguration? configurations) { if (entityBatchRequest == null) { @@ -496,7 +496,7 @@ internal static P.PurgeInstancesResponse CreatePurgeInstancesResponse(PurgeResul var batchRequest = new P.EntityBatchRequest() { InstanceId = entityBatchRequest.InstanceId, - EntityState = configurations?.IncludeEntityState == false ? null : entityBatchRequest.EntityState, + EntityState = configurations?.IncludeState == false ? null : entityBatchRequest.EntityState, }; batchRequest.Properties.Add(ProtobufUtils.ConvertPocoToProtoMap(configurations)); diff --git a/src/WebJobs.Extensions.DurableTask/RemoteEntityConfiguration.cs b/src/WebJobs.Extensions.DurableTask/RemoteEntityConfiguration.cs deleted file mode 100644 index e5198c454..000000000 --- a/src/WebJobs.Extensions.DurableTask/RemoteEntityConfiguration.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. See LICENSE in the project root for license information. - -namespace Microsoft.Azure.WebJobs.Extensions.DurableTask -{ - /// - /// Configuration settings for RemoteEntityContext in out-of-process mode, transmitted via gRPC. - /// - public class RemoteEntityConfiguration - { - /// - /// Gets or sets whether or not to include the entity state in the entity batch request. - /// - public bool IncludeEntityState { get; set; } = true; - - /// - /// Gets or sets whether or not the entity batch request is within an extended session. - /// - public bool ExtendedSession { get; set; } = false; - - /// - /// Gets or sets the amount of time in seconds before an idle extended session times out. - /// - public int ExtendedSessionIdleTimeoutInSeconds { get; set; } - } -} diff --git a/src/WebJobs.Extensions.DurableTask/RemoteOrchestratorConfiguration.cs b/src/WebJobs.Extensions.DurableTask/RemoteInstanceConfiguration.cs similarity index 83% rename from src/WebJobs.Extensions.DurableTask/RemoteOrchestratorConfiguration.cs rename to src/WebJobs.Extensions.DurableTask/RemoteInstanceConfiguration.cs index 5b38f88ab..f379830e8 100644 --- a/src/WebJobs.Extensions.DurableTask/RemoteOrchestratorConfiguration.cs +++ b/src/WebJobs.Extensions.DurableTask/RemoteInstanceConfiguration.cs @@ -6,7 +6,7 @@ namespace Microsoft.Azure.WebJobs.Extensions.DurableTask /// /// Configuration settings for RemoteOrchestratorContext in out-of-process mode, transmitted via gRPC. /// - public class RemoteOrchestratorConfiguration + public class RemoteInstanceConfiguration { /// /// Gets or sets the default number of milliseconds between async HTTP status poll requests. @@ -14,10 +14,10 @@ public class RemoteOrchestratorConfiguration public int HttpDefaultAsyncRequestSleepTimeMilliseconds { get; set; } = 30000; /// - /// Gets or sets whether or not to include the past history events in the orchestration request. + /// Gets or sets whether or not to include the instance state in the instance request. /// True by default. /// - public bool IncludePastEvents { get; set; } = true; + public bool IncludeState { get; set; } = true; /// /// Gets or sets whether or not the orchestration request is within an extended session. From f017ab3100236cb7eab582f8c1d01324db81371a Mon Sep 17 00:00:00 2001 From: Sophia Tevosyan Date: Tue, 2 Dec 2025 14:02:42 -0800 Subject: [PATCH 4/4] changed the class and fields to internal --- .../RemoteInstanceConfiguration.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/WebJobs.Extensions.DurableTask/RemoteInstanceConfiguration.cs b/src/WebJobs.Extensions.DurableTask/RemoteInstanceConfiguration.cs index f379830e8..b1325b62b 100644 --- a/src/WebJobs.Extensions.DurableTask/RemoteInstanceConfiguration.cs +++ b/src/WebJobs.Extensions.DurableTask/RemoteInstanceConfiguration.cs @@ -4,30 +4,31 @@ namespace Microsoft.Azure.WebJobs.Extensions.DurableTask { /// - /// Configuration settings for RemoteOrchestratorContext in out-of-process mode, transmitted via gRPC. + /// Configuration settings for and + /// in out-of-process mode, transmitted via gRPC. /// - public class RemoteInstanceConfiguration + internal class RemoteInstanceConfiguration { /// /// Gets or sets the default number of milliseconds between async HTTP status poll requests. /// - public int HttpDefaultAsyncRequestSleepTimeMilliseconds { get; set; } = 30000; + internal int HttpDefaultAsyncRequestSleepTimeMilliseconds { get; set; } = 30000; /// /// Gets or sets whether or not to include the instance state in the instance request. /// True by default. /// - public bool IncludeState { get; set; } = true; + internal bool IncludeState { get; set; } = true; /// /// Gets or sets whether or not the orchestration request is within an extended session. /// False by default. /// - public bool IsExtendedSession { get; set; } = false; + internal bool IsExtendedSession { get; set; } = false; /// /// Gets or sets the amount of time in seconds before an idle extended session times out. /// - public int ExtendedSessionIdleTimeoutInSeconds { get; set; } + internal int ExtendedSessionIdleTimeoutInSeconds { get; set; } } }