Skip to content

Instantly share code, notes, and snippets.

@wdspider
Last active July 17, 2018 12:02
Show Gist options
  • Save wdspider/a1cf8328dbcf6cd42ea0a889f5427f0b to your computer and use it in GitHub Desktop.
Save wdspider/a1cf8328dbcf6cd42ea0a889f5427f0b to your computer and use it in GitHub Desktop.
Example of Polly Timeout Policy not working as expected. ( .NET Core 2.1 console app)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.6" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Http" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="2.1.1" />
</ItemGroup>
</Project>
namespace PollyTimeoutDemo
{
using System;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Polly;
using Polly.Timeout;
class Program
{
static async Task Main(string[] args)
{
try
{
Console.WriteLine("Building Service Provider");
TimeoutPolicy<HttpResponseMessage> timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(5, TimeoutStrategy.Optimistic);
IServiceCollection services = new ServiceCollection()
.AddTransient<ClientLoggingHandler>();
services.AddHttpClient<IMyClient, MyClient>()
.AddHttpMessageHandler<ClientLoggingHandler>()
.AddPolicyHandler(timeoutPolicy);
ServiceProvider serviceProvider = services.BuildServiceProvider();
Console.WriteLine("Getting client");
IMyClient myClient = serviceProvider.GetService<IMyClient>();
ClientResponse response = await myClient.SendRequest(new ClientRequest());
}
catch(Exception ex) { PrintException(ex); }
Console.ReadKey();
}
static void PrintException(Exception ex)
{
Console.WriteLine();
while (ex != null)
{
Console.WriteLine(ex.ToString());
Console.WriteLine();
ex = ex.InnerException;
}
}
}
class ClientResponse { }
class ClientRequest { }
interface IMyClient
{
Task<ClientResponse> SendRequest(ClientRequest request);
}
class MyClient : IMyClient
{
private readonly HttpClient httpClient;
public MyClient(HttpClient httpClient) => this.httpClient = httpClient;
public async Task<ClientResponse> SendRequest(ClientRequest request)
{
HttpResponseMessage response = await httpClient.PostAsJsonAsync("http://www.google.com", request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsAsync<ClientResponse>();
}
}
class ClientLoggingHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
ValueStopwatch stopwatch = ValueStopwatch.Start();
Console.WriteLine("Starting Request");
await Task.Delay(TimeSpan.FromSeconds(20), cancellationToken);
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
TimeSpan duration = stopwatch.Elasped();
Console.WriteLine($"Finished Request: {duration}");
return response;
}
}
public struct ValueStopwatch
{
#region Internal State
private static readonly double TimestampTicks = TimeSpan.TicksPerSecond / (double)Stopwatch.Frequency;
private long startTimestamp;
#endregion
private ValueStopwatch(long startTimestamp) => this.startTimestamp = startTimestamp;
#region Methods
public static ValueStopwatch Start() => new ValueStopwatch(Stopwatch.GetTimestamp());
public TimeSpan Elasped()
{
if (startTimestamp == 0) throw new InvalidOperationException($"{nameof(ValueStopwatch)} has not been initialized yet.");
return new TimeSpan((long)(TimestampTicks * (Stopwatch.GetTimestamp() - startTimestamp)));
}
#endregion
}
}
@reisenberger
Copy link

Reverse the order of delegating handlers as below, and the timeout works:

services.AddHttpClient<IMyClient, MyClient>()
                .AddPolicyHandler(timeoutPolicy)
                .AddHttpMessageHandler<ClientLoggingHandler>();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment