Skip to content

Commit

Permalink
Add gRPC retries to client
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesNK committed Feb 17, 2021
1 parent 08024e3 commit 349c91f
Show file tree
Hide file tree
Showing 76 changed files with 7,017 additions and 292 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<WarningsNotAsErrors>$(WarningsNotAsErrors);CS1591</WarningsNotAsErrors>

<EmbedUntrackedSources>true</EmbedUntrackedSources>
<LangVersion>8.0</LangVersion>
<LangVersion>9.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>

Expand Down
20 changes: 20 additions & 0 deletions examples/Retrier/Client/Client.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Protobuf Include="..\Proto\retry.proto" GrpcServices="Client" Link="Protos\retry.proto" />

<PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufPackageVersion)" />
<PackageReference Include="Grpc.Tools" Version="$(GrpcPackageVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Grpc.Net.Client\Grpc.Net.Client.csproj" />
</ItemGroup>
</Project>
195 changes: 195 additions & 0 deletions examples/Retrier/Client/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
#region Copyright notice and license

// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#endregion

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using Grpc.Net.Client;
using Grpc.Net.Client.Configuration;
using Retry;

namespace Client
{
public class Program
{
static async Task Main(string[] args)
{
using var channel = CreateChannel();
var client = new Retrier.RetrierClient(channel);

//await UnaryRetry(client);
await StreamingRetry(client);

Console.WriteLine("Shutting down");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}

private static async Task UnaryRetry(Retrier.RetrierClient client)
{
Console.WriteLine("Delivering packages...");
foreach (var product in Products)
{
try
{
var package = new Package { Name = product };
var call = client.DeliverPackageAsync(package);
var response = await call;

#region Print success
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(response.Message);
Console.ResetColor();
Console.Write(" " + await GetRetryCount(call.ResponseHeadersAsync));
Console.WriteLine();
#endregion
}
catch (RpcException ex)
{
#region Print failure
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex.Status.Detail);
Console.ResetColor();
#endregion
}

await Task.Delay(TimeSpan.FromSeconds(0.2));
}
}

private static async Task StreamingRetry(Retrier.RetrierClient client)
{
var call = client.MessageUpload();

try
{
var lines = ImportantMessage.Split(Environment.NewLine);
for (var i = 0; i < lines.Length; i++)
{
#region Print percentage
if (i % 2 == 0)
{
Console.WriteLine((int)((i + 1D) / lines.Length * 100) + "% uploaded");
}
#endregion

await call.RequestStream.WriteAsync(new StringValue { Value = lines[i] });
await Task.Delay(TimeSpan.FromSeconds(0.1));
}
await call.RequestStream.CompleteAsync();

Console.WriteLine("Upload complete");
Console.WriteLine("Press any key to download important message...");
Console.ReadKey();

#region Print success
var count = 0;
await foreach (var line in call.ResponseStream.ReadAllAsync())
{
Console.ForegroundColor = (ConsoleColor)(count % 7) + 9;
Console.WriteLine(line.Value);
await Task.Delay(TimeSpan.FromSeconds(0.2));
count++;
}
Console.ResetColor();
Console.Write(" " + await GetRetryCount(call.ResponseHeadersAsync));
Console.WriteLine();
#endregion
}
catch (RpcException ex)
{
#region Print failure
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex.Status.Detail);
Console.ResetColor();
#endregion
}
}

private static GrpcChannel CreateChannel()
{
var options = new GrpcChannelOptions
{
ServiceConfig = new ServiceConfig
{
MethodConfigs =
{
new MethodConfig
{
Names = { MethodName.Default },
}
}
}
};
return GrpcChannel.ForAddress("http://localhost:5000", options);
}

private static async Task<string> GetRetryCount(Task<Metadata> responseHeadersTask)
{
var headers = await responseHeadersTask;
var previousAttemptCount = headers.GetValue("grpc-previous-rpc-attempts");
return previousAttemptCount != null ? $"(retry count: {previousAttemptCount})" : string.Empty;
}

private static readonly IList<string> Products = new List<string>
{
"Secrets of Silicon Valley",
"The Busy Executive's Database Guide",
"Emotional Security: A New Algorithm",
"Prolonged Data Deprivation: Four Case Studies",
"Cooking with Computers: Surreptitious Balance Sheets",
"Silicon Valley Gastronomic Treats",
"Sushi, Anyone?",
"Fifty Years in Buckingham Palace Kitchens",
"But Is It User Friendly?",
"You Can Combat Computer Stress!",
"Is Anger the Enemy?",
"Life Without Fear",
"The Gourmet Microwave",
"Onions, Leeks, and Garlic: Cooking Secrets of the Mediterranean",
"The Psychology of Computer Cooking",
"Straight Talk About Computers",
"Computer Phobic AND Non-Phobic Individuals: Behavior Variations",
"Net Etiquette"
};

private static readonly string ImportantMessage =@"
_____ _____ _____
| __ \| __ \ / ____|
__ _| |__) | |__) | |
/ _` | _ /| ___/| |
| (_| | | \ \| | | |____
\__, |_| \_\_| \_____|
__/ |
|___/
_
(_)
_ ___
| / __|
| \__ \ _
|_|___/ | |
___ ___ ___ | |
/ __/ _ \ / _ \| |
| (_| (_) | (_) | |
\___\___/ \___/|_|
";
}
}
32 changes: 32 additions & 0 deletions examples/Retrier/Proto/retry.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

import "google/protobuf/wrappers.proto";

package retry;

service Retrier {
rpc DeliverPackage (Package) returns (Response);
rpc MessageUpload (stream google.protobuf.StringValue) returns (stream google.protobuf.StringValue);
}

message Package {
string name = 1;
}

message Response {
string message = 1;
}
43 changes: 43 additions & 0 deletions examples/Retrier/Retrier.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29230.61
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.Client", "..\..\src\Grpc.Net.Client\Grpc.Net.Client.csproj", "{F001F7FD-21F7-42E5-BFB6-D0136ACA8869}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.Common", "..\..\src\Grpc.Net.Common\Grpc.Net.Common.csproj", "{EB47A4E0-1AED-4D44-8BF6-BC7AE00D4058}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Release|Any CPU.Build.0 = Release|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Release|Any CPU.Build.0 = Release|Any CPU
{F001F7FD-21F7-42E5-BFB6-D0136ACA8869}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F001F7FD-21F7-42E5-BFB6-D0136ACA8869}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F001F7FD-21F7-42E5-BFB6-D0136ACA8869}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F001F7FD-21F7-42E5-BFB6-D0136ACA8869}.Release|Any CPU.Build.0 = Release|Any CPU
{EB47A4E0-1AED-4D44-8BF6-BC7AE00D4058}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB47A4E0-1AED-4D44-8BF6-BC7AE00D4058}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB47A4E0-1AED-4D44-8BF6-BC7AE00D4058}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB47A4E0-1AED-4D44-8BF6-BC7AE00D4058}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D22B3129-3BFB-41FA-9FCE-E45EBEF8C2DD}
EndGlobalSection
EndGlobal
38 changes: 38 additions & 0 deletions examples/Retrier/Server/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#region Copyright notice and license

// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#endregion

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace Server
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
13 changes: 13 additions & 0 deletions examples/Retrier/Server/Server.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Protobuf Include="..\Proto\retry.proto" GrpcServices="Server" Link="Protos\retry.proto" />

<PackageReference Include="Grpc.AspNetCore" Version="$(GrpcDotNetPackageVersion)" />
</ItemGroup>

</Project>
Loading

0 comments on commit 349c91f

Please sign in to comment.