Skip to content

Instantly share code, notes, and snippets.

@pedrovasconcellos
Last active March 8, 2024 03:57
Show Gist options
  • Save pedrovasconcellos/cf2b8dcde14313e19a891408c3404337 to your computer and use it in GitHub Desktop.
Save pedrovasconcellos/cf2b8dcde14313e19a891408c3404337 to your computer and use it in GitHub Desktop.
Example using restsharp with polly
using Polly;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading.Tasks;
namespace RestSharpWithPolly
{
public class HttpCommunication
{
private static int _maxRetryAttempts = 5;
private static TimeSpan _pauseBetweenFailures = TimeSpan.FromSeconds(10);
public static void SetMaxRetryAttemptsAndPauseBetweenFailures(int maxRetryAttempts, TimeSpan pauseBetweenFailures)
{
_maxRetryAttempts = maxRetryAttempts;
_pauseBetweenFailures = pauseBetweenFailures;
}
public async Task<IRestResponse> HttpAsync(Method httpVerb, string hostUrl, Dictionary<string, string> headers, object requestObject, Func<string, Task> logFunction)
{
var restResponse = default(IRestResponse);
try
{
var restRequest = new RestRequest(httpVerb);
restRequest.AddHeader("cache-control", "no-cache");
if (headers != null && headers.Count > 0)
foreach (var header in headers)
restRequest.AddHeader(header.Key, header.Value);
var json = this.JsonSerialize(requestObject);
if(httpVerb != Method.GET)
{
restRequest.RequestFormat = DataFormat.Json;
restRequest.AddParameter("application/json; charset=utf-8", json, ParameterType.RequestBody);
}
restResponse = this.RestResponseWithPolicy(new RestClient(hostUrl), restRequest, logFunction);
}
catch (Exception ex)
{
restResponse = new RestResponse
{
Content = ex.Message,
ErrorMessage = ex.Message,
ResponseStatus = ResponseStatus.TimedOut,
StatusCode = HttpStatusCode.ServiceUnavailable
};
}
return await Task.FromResult(restResponse);
}
private IRestResponse RestResponseWithPolicy(RestClient restClient, RestRequest restRequest, Func<string, Task> logFunction)
{
var retryPolicy = Policy
.HandleResult<IRestResponse>(x => !x.IsSuccessful)
.WaitAndRetry(_maxRetryAttempts, x => _pauseBetweenFailures, async (iRestResponse, timeSpan, retryCount, context) =>
{
await logFunction($"The request failed. HttpStatusCode={iRestResponse.Result.StatusCode}. Waiting {timeSpan} seconds before retry. Number attempt {retryCount}. Uri={iRestResponse.Result.ResponseUri}; RequestResponse={iRestResponse.Result.Content}");
});
var circuitBreakerPolicy = Policy
.HandleResult<IRestResponse>(x => x.StatusCode == HttpStatusCode.ServiceUnavailable)
.CircuitBreaker(1, TimeSpan.FromSeconds(60), onBreak: async (iRestResponse, timespan, context) =>
{
await logFunction($"Circuit went into a fault state. Reason: {iRestResponse.Result.Content}");
},
onReset: async (context) =>
{
await logFunction($"Circuit left the fault state.");
});
return retryPolicy.Wrap(circuitBreakerPolicy).Execute(() => restClient.Execute(restRequest));
}
private string JsonSerialize(object obj) => JsonSerializer.Serialize(obj, this.GetJsonSerializerOptions());
private JsonSerializerOptions GetJsonSerializerOptions() => new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment