我目前正在使用Polly来限制我发送的请求数量。这是我目前拥有的政策:
private AsyncPolicyWrap<HttpResponseMessage> DefineAndRetrieveResiliencyStrategy()
{
HttpStatusCode[] retryCodes = {
HttpStatusCode.InternalServerError,
HttpStatusCode.BadGateway,
HttpStatusCode.GatewayTimeout
};
var waitAndRetryPolicy = Policy
.HandleResult<HttpResponseMessage>(e => e.StatusCode == HttpStatusCode.ServiceUnavailable || e.StatusCode == (HttpStatusCode)429)
.WaitAndRetryAsync(10,
attempt => TimeSpan.FromSeconds(5), (exception, calculatedWaitDuration) =>
{
_log.Info($"Bitfinex API server is throttling our requests. Automatically delaying for {calculatedWaitDuration.TotalMilliseconds}ms");
}
);
var circuitBreakerPolicyForRecoverable = Policy
.Handle<HttpResponseException>()
.OrResult<HttpResponseMessage>(r => retryCodes.Contains(r.StatusCode))
.CircuitBreakerAsync(
handledEventsAllowedBeforeBreaking: 3,
durationOfBreak: TimeSpan.FromSeconds(3),
onBreak: (outcome, breakDelay) =>
{
_log.Info($"Polly Circuit Breaker logging: Breaking the circuit for {breakDelay.TotalMilliseconds}ms due to: {outcome.Exception?.Message ?? outcome.Result.StatusCode.ToString()}");
},
onReset: () => _log.Info("Polly Circuit Breaker logging: Call ok... closed the circuit again"),
onHalfOpen: () => _log.Info("Polly Circuit Breaker logging: Half-open: Next call is a trial")
);
return Policy.WrapAsync(waitAndRetryPolicy, circuitBreakerPolicyForRecoverable);
}
我有以下请求发送者:
private async Task<string> SendRequest(GenericRequest request, string httpMethod, string publicKey, string privateKey)
{
var resiliencyStrategy = DefineAndRetrieveResiliencyStrategy();
using (var client = new HttpClient())
using (var httpRequest = new HttpRequestMessage(new HttpMethod(httpMethod), request.request))
{
string json = JsonConvert.SerializeObject(request);
string json64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(json));
byte[] data = Encoding.UTF8.GetBytes(json64);
client.BaseAddress = new Uri(Properties.Settings.Default.BitfinexUri);
var hashMaker = new HMACSHA384(Encoding.UTF8.GetBytes(privateKey));
byte[] hash = hashMaker.ComputeHash(data);
string signature = GetHexString(hash);
httpRequest.Headers.Add("X-BFX-APIKEY", publicKey);
httpRequest.Headers.Add("X-BFX-PAYLOAD", json64);
httpRequest.Headers.Add("X-BFX-SIGNATURE", signature);
var message = await resiliencyStrategy.ExecuteAsync(() => client.SendAsync(httpRequest));
var response = message.Content.ReadAsStringAsync().Result;
return response;
}
}
代码一旦达到waitAndRetryPolicy并等待所需的时间,就会收到以下错误:
System.InvalidOperationException:'请求消息已发送。无法多次发送相同的请求消息。'
我知道发生这种情况是因为我再次发送了相同的HttpRequest,但是Polly库不应该处理这样的问题吗?
答案 0 :(得分:1)
那个例外:
如果您thrown by the internals ofSystem.InvalidOperationException:'请求消息已发送。无法多次发送相同的请求消息。'
HttpClient
,
如果您使用的是.NET Core,建议的解决方案是使用Polly with HttpClientFactory:这通过在from django.utils import safestring
def __str__(self):
string = safestring.mark_safe("more spaces {}"+" "*10+ "{}!".format(self.foo, self.bar))
return string
中通过DelegatingHandler
执行策略(例如重试)来解决上述异常。 。它还解决了socket-exhaustion problem的问题,该问题可能是由于频繁创建/处置HttpClient
而引起的,问题中张贴的代码可能容易受到攻击。
如果您使用.NET Framework,则推荐的解决方案是:
HttpClient
的新实例(或克隆现有实例)。This stackoverflow question广泛讨论了该问题以及上述解决方案的许多变体。