Skip to content

Commit 01283c5

Browse files
authored
Merge branch 'grpc:master' into feature/MapGrpcService-with-ServerServiceDefinition
2 parents 2bdd1c8 + d170b24 commit 01283c5

File tree

7 files changed

+260
-214
lines changed

7 files changed

+260
-214
lines changed

Directory.Packages.props

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<Project>
22
<PropertyGroup>
33
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
4-
<MicrosoftAspNetCoreAppPackageVersion>9.0.0</MicrosoftAspNetCoreAppPackageVersion>
5-
<MicrosoftAspNetCoreApp8PackageVersion>8.0.6</MicrosoftAspNetCoreApp8PackageVersion>
6-
<MicrosoftAspNetCoreApp7PackageVersion>7.0.5</MicrosoftAspNetCoreApp7PackageVersion>
7-
<MicrosoftAspNetCoreApp6PackageVersion>6.0.33</MicrosoftAspNetCoreApp6PackageVersion>
8-
<GrpcDotNetPackageVersion>2.66.0</GrpcDotNetPackageVersion>
4+
<MicrosoftAspNetCoreAppPackageVersion>9.0.4</MicrosoftAspNetCoreAppPackageVersion>
5+
<MicrosoftAspNetCoreApp8PackageVersion>8.0.15</MicrosoftAspNetCoreApp8PackageVersion>
6+
<MicrosoftAspNetCoreApp7PackageVersion>7.0.20</MicrosoftAspNetCoreApp7PackageVersion>
7+
<MicrosoftAspNetCoreApp6PackageVersion>6.0.36</MicrosoftAspNetCoreApp6PackageVersion>
8+
<GrpcDotNetPackageVersion>2.70.0</GrpcDotNetPackageVersion>
99
<OpenTelemetryPackageVersion>1.6.0</OpenTelemetryPackageVersion>
1010
<OpenTelemetryIntergationPackageVersion>1.8.1</OpenTelemetryIntergationPackageVersion>
1111
<OpenTelemetryGrpcPackageVersion>1.8.0-beta.1</OpenTelemetryGrpcPackageVersion>
@@ -33,7 +33,7 @@
3333
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
3434

3535
<!-- gRPC -->
36-
<PackageVersion Include="Grpc.Tools" Version="2.70.0" />
36+
<PackageVersion Include="Grpc.Tools" Version="2.71.0" />
3737
<PackageVersion Include="Grpc.Core" Version="2.46.6" />
3838
<PackageVersion Include="Grpc.Core.Api" Version="$(GrpcDotNetPackageVersion)"/>
3939
<PackageVersion Include="Grpc.Net.Client" Version="$(GrpcDotNetPackageVersion)" />
@@ -47,6 +47,7 @@
4747
<PackageVersion Include="Grpc.HealthCheck" Version="$(GrpcDotNetPackageVersion)" />
4848
<PackageVersion Include="Grpc.AspNetCore.HealthChecks" Version="$(GrpcDotNetPackageVersion)" />
4949
<PackageVersion Include="Grpc.Auth" Version="$(GrpcDotNetPackageVersion)" />
50+
<PackageVersion Include="Grpc.StatusProto" Version="$(GrpcDotNetPackageVersion)" />
5051

5152
<!-- OpenTelemetry -->
5253
<PackageVersion Include="OpenTelemetry" Version="$(OpenTelemetryPackageVersion)" />
@@ -59,9 +60,9 @@
5960
<!-- Other -->
6061
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0" />
6162
<PackageVersion Include="CommandLineParser" Version="2.5.0" />
62-
<PackageVersion Include="Google.Api.CommonProtos" Version="2.15.0" />
63-
<PackageVersion Include="Google.Apis.Auth" Version="1.68.0" />
64-
<PackageVersion Include="Google.Protobuf" Version="3.27.0" />
63+
<PackageVersion Include="Google.Api.CommonProtos" Version="2.16.0" />
64+
<PackageVersion Include="Google.Apis.Auth" Version="1.69.0" />
65+
<PackageVersion Include="Google.Protobuf" Version="3.30.2" />
6566
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0" />
6667
<PackageVersion Include="Microsoft.Build.Locator" Version="1.5.5" />
6768
<PackageVersion Include="Microsoft.Build" Version="17.3.2" />

examples/Error/Client/Client.csproj

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,9 @@
88
<ItemGroup>
99
<Protobuf Include="..\Proto\greet.proto" GrpcServices="Client" Link="Protos\greet.proto" />
1010

11-
<PackageReference Include="Google.Protobuf" VersionOverride="3.25.0" />
11+
<PackageReference Include="Google.Protobuf" />
12+
<PackageReference Include="Grpc.Net.Client" />
13+
<PackageReference Include="Grpc.StatusProto" />
1214
<PackageReference Include="Grpc.Tools" PrivateAssets="All" />
1315
</ItemGroup>
14-
15-
<ItemGroup>
16-
<!-- Project references required until Grpc.StatusProto is on nuget.org -->
17-
<ProjectReference Include="..\..\..\src\Grpc.Net.Client\Grpc.Net.Client.csproj" />
18-
<ProjectReference Include="..\..\..\src\Grpc.StatusProto\Grpc.StatusProto.csproj" />
19-
</ItemGroup>
2016
</Project>

examples/Error/Error.sln

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csp
77
EndProject
88
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}"
99
EndProject
10-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.StatusProto", "..\..\src\Grpc.StatusProto\Grpc.StatusProto.csproj", "{08BEBE52-D94B-449B-A5B5-9ABAABDE7CB2}"
11-
EndProject
12-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Core.Api", "..\..\src\Grpc.Core.Api\Grpc.Core.Api.csproj", "{E00E8BDE-19A9-47D7-B2D8-B304B2DEBAF3}"
13-
EndProject
14-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.Client", "..\..\src\Grpc.Net.Client\Grpc.Net.Client.csproj", "{E2C141A0-E21F-4F0F-9E32-FD90C57E8AD0}"
15-
EndProject
16-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.Common", "..\..\src\Grpc.Net.Common\Grpc.Net.Common.csproj", "{23678E37-37D4-4543-9961-403B3760862B}"
17-
EndProject
18-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.AspNetCore.Server", "..\..\src\Grpc.AspNetCore.Server\Grpc.AspNetCore.Server.csproj", "{A1368174-6D27-49F1-B6DC-F1868CAE000F}"
19-
EndProject
2010
Global
2111
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2212
Debug|Any CPU = Debug|Any CPU
@@ -31,26 +21,6 @@ Global
3121
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Debug|Any CPU.Build.0 = Debug|Any CPU
3222
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Release|Any CPU.ActiveCfg = Release|Any CPU
3323
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Release|Any CPU.Build.0 = Release|Any CPU
34-
{08BEBE52-D94B-449B-A5B5-9ABAABDE7CB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35-
{08BEBE52-D94B-449B-A5B5-9ABAABDE7CB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
36-
{08BEBE52-D94B-449B-A5B5-9ABAABDE7CB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
37-
{08BEBE52-D94B-449B-A5B5-9ABAABDE7CB2}.Release|Any CPU.Build.0 = Release|Any CPU
38-
{E00E8BDE-19A9-47D7-B2D8-B304B2DEBAF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39-
{E00E8BDE-19A9-47D7-B2D8-B304B2DEBAF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
40-
{E00E8BDE-19A9-47D7-B2D8-B304B2DEBAF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
41-
{E00E8BDE-19A9-47D7-B2D8-B304B2DEBAF3}.Release|Any CPU.Build.0 = Release|Any CPU
42-
{E2C141A0-E21F-4F0F-9E32-FD90C57E8AD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43-
{E2C141A0-E21F-4F0F-9E32-FD90C57E8AD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
44-
{E2C141A0-E21F-4F0F-9E32-FD90C57E8AD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
45-
{E2C141A0-E21F-4F0F-9E32-FD90C57E8AD0}.Release|Any CPU.Build.0 = Release|Any CPU
46-
{23678E37-37D4-4543-9961-403B3760862B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47-
{23678E37-37D4-4543-9961-403B3760862B}.Debug|Any CPU.Build.0 = Debug|Any CPU
48-
{23678E37-37D4-4543-9961-403B3760862B}.Release|Any CPU.ActiveCfg = Release|Any CPU
49-
{23678E37-37D4-4543-9961-403B3760862B}.Release|Any CPU.Build.0 = Release|Any CPU
50-
{A1368174-6D27-49F1-B6DC-F1868CAE000F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
51-
{A1368174-6D27-49F1-B6DC-F1868CAE000F}.Debug|Any CPU.Build.0 = Debug|Any CPU
52-
{A1368174-6D27-49F1-B6DC-F1868CAE000F}.Release|Any CPU.ActiveCfg = Release|Any CPU
53-
{A1368174-6D27-49F1-B6DC-F1868CAE000F}.Release|Any CPU.Build.0 = Release|Any CPU
5424
EndGlobalSection
5525
GlobalSection(SolutionProperties) = preSolution
5626
HideSolutionNode = FALSE

examples/Error/Server/Server.csproj

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,8 @@
77
<ItemGroup>
88
<Protobuf Include="..\Proto\greet.proto" GrpcServices="Server" Link="Protos\greet.proto" />
99

10-
<PackageReference Include="Google.Protobuf" VersionOverride="3.25.0" />
11-
<PackageReference Include="Grpc.Tools" />
12-
</ItemGroup>
13-
14-
<ItemGroup>
15-
<!-- Project references required until Grpc.StatusProto is on nuget.org -->
16-
<ProjectReference Include="..\..\..\src\Grpc.AspNetCore.Server\Grpc.AspNetCore.Server.csproj" />
17-
<ProjectReference Include="..\..\..\src\Grpc.StatusProto\Grpc.StatusProto.csproj" />
10+
<PackageReference Include="Grpc.StatusProto" />
11+
<PackageReference Include="Grpc.AspNetCore" />
1812
</ItemGroup>
1913

2014
</Project>

src/Grpc.Net.Client/Balancer/Subchannel.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -266,10 +266,10 @@ public void RequestConnection()
266266
}
267267
}
268268

269-
if (connectionRequested)
270-
{
271-
UpdateConnectivityState(ConnectivityState.Connecting, "Connection requested.");
272-
}
269+
Debug.Assert(connectionRequested, "Ensure that only expected state made it to this point.");
270+
271+
SubchannelLog.StartingConnectionRequest(_logger, Id);
272+
UpdateConnectivityState(ConnectivityState.Connecting, "Connection requested.");
273273

274274
// Don't capture the current ExecutionContext and its AsyncLocals onto the connect
275275
var restoreFlow = false;
@@ -327,6 +327,15 @@ private async Task ConnectTransportAsync()
327327
return;
328328
}
329329

330+
// There is already a connect in-progress on this transport.
331+
// Don't cancel and start again as that causes queued requests waiting on the connect to fail.
332+
if (_connectContext != null && !_connectContext.Disposed)
333+
{
334+
SubchannelLog.ConnectionRequestedInNonIdleState(_logger, Id, _state);
335+
_delayInterruptTcs?.TrySetResult(null);
336+
return;
337+
}
338+
330339
connectContext = GetConnectContextUnsynchronized();
331340

332341
// Use a semaphore to limit one connection attempt at a time. This is done to prevent a race conditional where a canceled connect
@@ -633,7 +642,11 @@ public static void AddressesUpdated(ILogger logger, string subchannelId, IReadOn
633642
AddressesUpdated(logger, subchannelId, addressesText);
634643
}
635644
}
645+
636646
[LoggerMessage(Level = LogLevel.Debug, EventId = 20, EventName = "QueuingConnect", Message = "Subchannel id '{SubchannelId}' queuing connect because a connect is already in progress.")]
637647
public static partial void QueuingConnect(ILogger logger, string subchannelId);
648+
649+
[LoggerMessage(Level = LogLevel.Trace, EventId = 21, EventName = "StartingConnectionRequest", Message = "Subchannel id '{SubchannelId}' starting connection request.")]
650+
public static partial void StartingConnectionRequest(ILogger logger, string subchannelId);
638651
}
639652
#endif

test/Grpc.Net.Client.Tests/Balancer/ConnectionManagerTests.cs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,128 @@ public async Task PickAsync_UpdateAddressesWhileRequestingConnection_DoesNotDead
620620
}
621621
}
622622

623+
[Test]
624+
public async Task PickAsync_MultipleRequestsRequestConnect_SingleConnectAttempt()
625+
{
626+
var services = new ServiceCollection();
627+
services.AddNUnitLogger();
628+
629+
var testSink = new TestSink();
630+
var testProvider = new TestLoggerProvider(testSink);
631+
632+
services.AddLogging(b =>
633+
{
634+
b.AddProvider(testProvider);
635+
});
636+
637+
await using var serviceProvider = services.BuildServiceProvider();
638+
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
639+
var logger = loggerFactory.CreateLogger(nameof(PickAsync_MultipleRequestsRequestConnect_SingleConnectAttempt));
640+
641+
var requestConnectionChannel = Channel.CreateUnbounded<SyncPoint>();
642+
var requestConnectionSyncPoint1 = new SyncPoint(runContinuationsAsynchronously: true);
643+
var requestConnectionSyncPoint2 = new SyncPoint(runContinuationsAsynchronously: true);
644+
requestConnectionChannel.Writer.TryWrite(requestConnectionSyncPoint1);
645+
requestConnectionChannel.Writer.TryWrite(requestConnectionSyncPoint2);
646+
647+
var connectingSyncPoint = new SyncPoint(runContinuationsAsynchronously: true);
648+
649+
var resolver = new TestResolver(loggerFactory);
650+
resolver.UpdateAddresses(new List<BalancerAddress>
651+
{
652+
new BalancerAddress("localhost", 80)
653+
});
654+
655+
var channelOptions = new GrpcChannelOptions();
656+
var acting = false;
657+
var transportFactory = TestSubchannelTransportFactory.Create(async (subChannel, attempt, cancellationToken) =>
658+
{
659+
cancellationToken.Register(() =>
660+
{
661+
logger.LogError("Connect cancellation token canceled.");
662+
});
663+
664+
if (!acting)
665+
{
666+
return new TryConnectResult(ConnectivityState.Ready);
667+
}
668+
669+
await connectingSyncPoint.WaitToContinue().WaitAsync(cancellationToken);
670+
671+
Assert.IsFalse(cancellationToken.IsCancellationRequested, "Cancellation token should not be canceled.");
672+
673+
return new TryConnectResult(ConnectivityState.Ready);
674+
});
675+
var clientChannel = CreateConnectionManager(loggerFactory, resolver, transportFactory, new[] { new PickFirstBalancerFactory() });
676+
// Configure balancer similar to how GrpcChannel constructor does it
677+
clientChannel.ConfigureBalancer(c => new ChildHandlerLoadBalancer(
678+
c,
679+
channelOptions.ServiceConfig,
680+
clientChannel));
681+
682+
await clientChannel.ConnectAsync(waitForReady: true, cancellationToken: CancellationToken.None);
683+
684+
transportFactory.Transports.ForEach(t => t.Disconnect());
685+
686+
testSink.MessageLogged += (w) =>
687+
{
688+
if (w.EventId.Name == "StartingConnectionRequest")
689+
{
690+
if (!requestConnectionChannel.Reader.TryRead(out var syncPoint))
691+
{
692+
throw new InvalidOperationException("Channel should have sync point.");
693+
}
694+
syncPoint.WaitToContinue().Wait();
695+
}
696+
};
697+
698+
acting = true;
699+
700+
logger.LogInformation("Start first pick.");
701+
var pickTask1 = Task.Run(() => clientChannel.PickAsync(
702+
new PickContext { Request = new HttpRequestMessage() },
703+
waitForReady: true,
704+
CancellationToken.None).AsTask());
705+
706+
logger.LogInformation("Wait for first pick to request connection.");
707+
await requestConnectionSyncPoint1.WaitForSyncPoint().DefaultTimeout();
708+
709+
logger.LogInformation("Start second pick.");
710+
var pickTask2 = Task.Run(() => clientChannel.PickAsync(
711+
new PickContext { Request = new HttpRequestMessage() },
712+
waitForReady: true,
713+
CancellationToken.None).AsTask());
714+
715+
logger.LogInformation("Wait for second pick to request connection.");
716+
await requestConnectionSyncPoint2.WaitForSyncPoint().DefaultTimeout();
717+
718+
logger.LogInformation("Allow first pick to start connecting.");
719+
requestConnectionSyncPoint1.Continue();
720+
await connectingSyncPoint.WaitForSyncPoint();
721+
722+
var connectionRequestedInNonIdleStateTcs = new TaskCompletionSource<object?>(TaskCreationOptions.RunContinuationsAsynchronously);
723+
testSink.MessageLogged += (w) =>
724+
{
725+
if (w.EventId.Name == "ConnectionRequestedInNonIdleState")
726+
{
727+
connectionRequestedInNonIdleStateTcs.TrySetResult(null);
728+
}
729+
};
730+
731+
logger.LogInformation("Allow second pick to wait for connecting to complete.");
732+
requestConnectionSyncPoint2.Continue();
733+
734+
logger.LogInformation("Wait for second pick to report that there is already a connection requested.");
735+
await connectionRequestedInNonIdleStateTcs.Task.DefaultTimeout();
736+
737+
logger.LogInformation("Allow first pick connecting to complete.");
738+
connectingSyncPoint.Continue();
739+
740+
logger.LogInformation("Wait for both picks to complete successfully.");
741+
await pickTask1.DefaultTimeout();
742+
await pickTask2.DefaultTimeout();
743+
}
744+
623745
[Test]
624746
public async Task PickAsync_ExecutionContext_DoesNotCaptureAsyncLocalsInConnect()
625747
{

0 commit comments

Comments
 (0)