Skip to content

Commit bc29ed5

Browse files
committed
test(durable): cover native-runtime gRPC protocol selection + clarify comment
Address review feedback on the native-runtime recognition change: - Update the protocol-selection comment to reflect that native (Go) and custom-handler runtimes also use the gRPC MiddlewarePassthrough protocol, not just .NET isolated and Java. - Add unit tests asserting Native/Golang select MiddlewarePassthrough (not the legacy HTTP shim). - Add unit tests asserting Native/Golang default UseSeparateQueueForEntityWorkItems=true, with an in-proc .NET counter-test.
1 parent c6bc9ac commit bc29ed5

3 files changed

Lines changed: 75 additions & 4 deletions

File tree

src/WebJobs.Extensions.DurableTask/DurableTaskExtension.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,11 @@ public DurableTaskExtension(
166166
this.telemetryActivator = telemetryActivator;
167167
this.telemetryActivator?.Initialize(logger);
168168

169-
// Starting with .NET isolated and Java, we have a more efficient out-of-process
170-
// function invocation protocol. Other languages will use the existing protocol.
169+
// The gRPC-based out-of-process invocation protocol (MiddlewarePassthrough) is the more
170+
// efficient protocol used by the compiled / newer-SDK runtimes: .NET isolated, Java, the
171+
// native worker (e.g. Go), and custom handlers. The remaining script languages (Python,
172+
// Node.js, PowerShell) start on the legacy HTTP protocol below and may upgrade to gRPC
173+
// during function indexing if their metadata requests it (see ConfigureForGrpcProtocol).
171174
WorkerRuntimeType runtimeType = this.PlatformInformationService.GetWorkerRuntimeType();
172175
if (runtimeType == WorkerRuntimeType.DotNetIsolated ||
173176
runtimeType == WorkerRuntimeType.Java ||

test/FunctionsV2/Tests/Unit/AzureStorageDurabilityProviderFactoryTests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,50 @@ public void ConsumptionDefaultsForPythonAreApplied()
7878
Assert.Equal(25, settings.MaxStorageOperationConcurrency);
7979
}
8080

81+
[Theory]
82+
[Trait("Category", PlatformSpecificHelpers.TestCategory)]
83+
[InlineData(WorkerRuntimeType.Native)]
84+
[InlineData(WorkerRuntimeType.Golang)]
85+
public void GrpcRuntimes_UseSeparateQueueForEntityWorkItems(WorkerRuntimeType runtimeType)
86+
{
87+
var clientProviderFactory = new TestStorageServiceClientProviderFactory();
88+
var mockOptions = new OptionsWrapper<DurableTaskOptions>(new DurableTaskOptions());
89+
var nameResolver = new Mock<INameResolver>().Object;
90+
var factory = new AzureStorageDurabilityProviderFactory(
91+
mockOptions,
92+
clientProviderFactory,
93+
nameResolver,
94+
NullLoggerFactory.Instance,
95+
TestHelpers.GetMockPlatformInformationService(language: runtimeType));
96+
97+
var settings = factory.GetAzureStorageOrchestrationServiceSettings();
98+
99+
// The native worker runtimes use the gRPC protocol, which requires a separate
100+
// queue for entity work items (matching .NET isolated / Java behavior).
101+
Assert.True(settings.UseSeparateQueueForEntityWorkItems);
102+
}
103+
104+
[Fact]
105+
[Trait("Category", PlatformSpecificHelpers.TestCategory)]
106+
public void InProcRuntime_DoesNotUseSeparateQueueForEntityWorkItems()
107+
{
108+
var clientProviderFactory = new TestStorageServiceClientProviderFactory();
109+
var mockOptions = new OptionsWrapper<DurableTaskOptions>(new DurableTaskOptions());
110+
var nameResolver = new Mock<INameResolver>().Object;
111+
var factory = new AzureStorageDurabilityProviderFactory(
112+
mockOptions,
113+
clientProviderFactory,
114+
nameResolver,
115+
NullLoggerFactory.Instance,
116+
TestHelpers.GetMockPlatformInformationService(language: WorkerRuntimeType.DotNet));
117+
118+
var settings = factory.GetAzureStorageOrchestrationServiceSettings();
119+
120+
// The in-process .NET runtime keeps the shared queue (this default is flipped
121+
// to true only for the gRPC-based runtimes).
122+
Assert.False(settings.UseSeparateQueueForEntityWorkItems);
123+
}
124+
81125
[Fact]
82126
[Trait("Category", PlatformSpecificHelpers.TestCategory)]
83127
public void ConsumptionDefaultsAreNotAlwaysApplied()

test/FunctionsV2/Tests/Unit/LocalGrpcListenerTests.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,31 @@ public void TestBindingHelper_ThrowsGrpcChannelUnavailableException_WhenGrpcAddr
502502
Assert.Contains("transient", ex.Message);
503503
}
504504

505+
/// <summary>
506+
/// Verifies that the native worker runtimes (the Go worker reports either "native" or,
507+
/// defensively, "golang") select the gRPC protocol (MiddlewarePassthrough) at extension
508+
/// initialization rather than the legacy HTTP-correlation shim (OrchestratorShim). When
509+
/// MiddlewarePassthrough is selected the local HTTP RPC server is never started — the
510+
/// runtime communicates durable operations over the local gRPC sidecar instead.
511+
/// </summary>
512+
[Theory]
513+
[Trait("Category", PlatformSpecificHelpers.TestCategory)]
514+
[InlineData(WorkerRuntimeType.Native)]
515+
[InlineData(WorkerRuntimeType.Golang)]
516+
public void TestNativeRuntime_SelectsGrpcProtocol(WorkerRuntimeType runtimeType)
517+
{
518+
using DurableTaskExtension extension = this.CreateExtension("NativeRuntimeProtocol", runtimeType);
519+
520+
Assert.Equal(OutOfProcOrchestrationProtocol.MiddlewarePassthrough, extension.OutOfProcProtocol);
521+
Assert.NotEqual(OutOfProcOrchestrationProtocol.OrchestratorShim, extension.OutOfProcProtocol);
522+
}
523+
505524
private DurableTaskExtension CreateExtension(string hubName)
525+
{
526+
return this.CreateExtension(hubName, WorkerRuntimeType.DotNetIsolated);
527+
}
528+
529+
private DurableTaskExtension CreateExtension(string hubName, WorkerRuntimeType runtimeType)
506530
{
507531
var options = new DurableTaskOptions { HubName = hubName };
508532
var wrappedOptions = new OptionsWrapper<DurableTaskOptions>(options);
@@ -512,7 +536,7 @@ private DurableTaskExtension CreateExtension(string hubName)
512536
new TestStorageServiceClientProviderFactory(),
513537
nameResolver,
514538
NullLoggerFactory.Instance,
515-
TestHelpers.GetMockPlatformInformationService(language: WorkerRuntimeType.DotNetIsolated));
539+
TestHelpers.GetMockPlatformInformationService(language: runtimeType));
516540

517541
return new DurableTaskExtension(
518542
wrappedOptions,
@@ -521,7 +545,7 @@ private DurableTaskExtension CreateExtension(string hubName)
521545
new[] { serviceFactory },
522546
new TestHostShutdownNotificationService(),
523547
new DurableHttpMessageHandlerFactory(),
524-
platformInformationService: TestHelpers.GetMockPlatformInformationService(language: WorkerRuntimeType.DotNetIsolated));
548+
platformInformationService: TestHelpers.GetMockPlatformInformationService(language: runtimeType));
525549
}
526550

527551
/// <summary>

0 commit comments

Comments
 (0)