我想在我的 C++ 程序中重试 curl 连接 5 次。当它连续 5 次失败时,它应该停止程序的执行。但是,此时它会在第一个错误后停止。我能够捕捉到错误,但是我不知道如何执行之前的 curl 连接。例如,使用 jQuery 我可以使用类似$.ajax(this);. 对于 C++ 中的 LibCurl,我正在寻找类似的解决方案。
我当前的 LibCurl 代码如下所示,请注意,我使用了多个 curl 连接,这些连接都有其他设置,因此我想要一种通用方法,可以用于我的LibcurlError函数中的所有 LibCurl 错误,该方法也包含在下面。
curl = curl_easy_init();
if (curl) {
CurlResponse = "";
host = "http://google.com";
LibcurlHeaders = curl_slist_append(NULL, "Expect:");
if (ProxyAddress.length() > 0) {
curl_easy_setopt(curl, CURLOPT_PROXY, ProxyAddress.c_str());
}
curl_easy_setopt(curl, CURLOPT_URL, (host).c_str());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER , 1);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST , 1);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, LibcurlHeaders);
res = curl_easy_perform(curl);
curl_slist_free_all(LibcurlHeaders);
if (res != CURLE_OK) {
//AT …Run Code Online (Sandbox Code Playgroud) 我必须与需要随每个请求发送访问令牌的外部服务集成。访问令牌的到期时间很短(只有几个小时)。我决定以乐观的方式使用访问令牌。我将使用当前令牌致电外部服务。我得到401的情况下,我将刷新令牌并再次调用外部API。
我决定使用ClientHttpRequestInterceptor来实现所描述的重试机制。
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
ClientHttpResponse response = execution.execute(request, body);
if(response.getStatusCode() == UNAUTHORIZED) {
refreshToken();
updateToken(request);
response = execution.execute(request, body);
}
return response;
}
Run Code Online (Sandbox Code Playgroud)
我已经对其进行了测试,并且可以运行,但是允许两次调用execution.execute()吗?我还没有发现任何禁止使用的信息,但是从另一方面来看,我也没有看到这样的代码。
我想实现http.Transport标准的自定义http.Client,如果客户端超时,它将自动重试。
PS 出于某种原因,定制http.Transport是必须具备的。我已经检查过hashcorp/go-retryablehttp,但是它不允许我使用我自己的http.Transport.
这是我的尝试,自定义组件:
type CustomTransport struct {
http.RoundTripper
// ... private fields
}
func NewCustomTransport(upstream *http.Transport) *CustomTransport {
upstream.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
// ... other customizations for transport
return &CustomTransport{upstream}
}
func (ct *CustomTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
req.Header.Set("Secret", "Blah blah blah")
// ... other customizations for each request
for i := 1; i <= 5; i++ {
resp, err = ct.RoundTripper.RoundTrip(req)
if errors.Is(err, …Run Code Online (Sandbox Code Playgroud) 我一直在努力寻找这个问题的答案,但找不到任何答案。
有很多技术可以让我们通过retrofit在OkHttp中实现重试并对其进行配置
根据文档https://square.github.io/okhttp/4.x/okhttp/okhttp3/-ok-http-client/-builder/retry-on-connection-failure/ fun retryOnConnectionFailure(retryOnConnectionFailure:Boolean):建设者
我们可以配置是否需要重试。默认值为 true。
但是OkHttp中默认的重试机制是什么呢
会拨打多少次电话?
OkHttp中默认的指数逻辑是什么?
任何人都可以帮忙吗
我正在尝试使用 polly 创建一个解决方案,其中我请求其他 api。
我有同一服务的多个实例的 URL 列表。
我希望当第一个请求失败时,另一个请求应该自动从我的列表中的下一个网址开始。
这是一个示例,我使用两个静态地址尝试此行为。
此解决方案的问题是,在我开始下一个请求之前,url 不会更改。我希望每次重试时网址都会改变
public static void ConfigureUserServiceClient(this IServiceCollection services)
{
_userServiceUri = new Uri("https://localhost:5001");
services.AddHttpClient("someService", client =>
{
client.BaseAddress = _userServiceUri;
client.DefaultRequestHeaders.Add("Accept", "application/json");
}).AddPolicyHandler(retryPolicy());
}
private static IAsyncPolicy<HttpResponseMessage> retryPolicy()
{
return Policy.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.RequestTimeout)
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(retryAttempt),
onRetry: (result, span, ctx) =>
{
_userServiceUri = new Uri("https://localhost:5002");
});
}
Run Code Online (Sandbox Code Playgroud) 该文档表明使用 aws sdk 为您提供开箱即用的重试功能。
然后这个文档指出
// The maximum number of times that a request will be retried for failures.
// Defaults to -1, which defers the max retry setting to the service
// specific configuration.
MaxRetries *int
Run Code Online (Sandbox Code Playgroud)
这告诉我重试逻辑配置发生在服务级别。
如果是这种情况,我希望各个服务记录其重试逻辑配置。实际情况不仅并非如此,一些服务(的操作)似乎暗示它们不提供重试逻辑,而是讨论如何在应用程序级别实现这一点。例如,参见dynamodb:
如果 DynamoDB 返回任何未处理的项目,您应该对这些项目重试批处理操作。但是,我们强烈建议您使用指数退避算法。如果您立即重试批处理操作,基础读取或写入请求仍可能因各个表上的限制而失败。如果使用指数退避来延迟批处理操作,则批处理中的各个请求更有可能成功。
和sqs:
接收请求尝试 ID 是用于 ReceiveMessage 调用的重复数据删除的令牌。
在导致开发工具包和 Amazon SQS 之间出现连接问题的长期网络中断期间,最佳实践是提供接收请求尝试 ID,并在开发工具包操作失败时使用相同的接收请求尝试 ID 重试。
我的问题是如何知道服务何时处理重试逻辑以及何时必须在应用程序级别实现它?
有人知道为什么下面的策略在 3 次而不是 10 次后停止重试吗?
IAsyncPolicy<HttpResponseMessage> httpWaitAndRetryPolicy =
Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.OrHandle<Exception>(r => true)
.WaitAndRetryAsync(10, retryAttempt => TimeSpan.FromSeconds(2));
Run Code Online (Sandbox Code Playgroud)
我将重试尝试设置为 10 并测试 http post 调用,但 BadRequest 失败。但只重试了3次就停止了,直到超时并抛出异常
IAsyncPolicy<HttpResponseMessage> httpWaitAndRetryPolicy =
Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.OrHandle<Exception>(r => true)
.WaitAndRetryAsync(10, retryAttempt => TimeSpan.FromSeconds(2));
Run Code Online (Sandbox Code Playgroud)
var serviceProvider = serviceConnection.AddHttpClient(connection.Name, c =>
{
c.BaseAddress = new Uri(connection.BaseUrl);
c.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{connection.UserName}:{connection.Password}")));
c.Timeout = connection.Timeout; // Timeout is TimeSpan.FromSeconds(120)
})
.AddPolicyHandler(httpWaitAndRetryPolicy)
.Services.BuildServiceProvider();
HttpClientFactories.Add(connection.Name, serviceProvider.GetService<IHttpClientFactory>());
Run Code Online (Sandbox Code Playgroud)
确认了问题的根本原因:我不知道是什么原因导致了该症状,但看起来请求连接不会被释放,除非显式调用Dispose HttpResponseMessage OnRetry. 当前的解决方案是设置OnRetry并WaitAndRetryAsync配置响应。一切正常,无需更改ServicePointManager.DefaultConnectionLimit
我刚刚读到Polly 库,当从桌面代理到服务器通信时,我需要处理 3 次重试。
目前我喜欢指数退避。
但是,我很难理解如何在我的代码中实现这一点。这是我到目前为止所做的:
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
client.DefaultRequestHeaders.Add("TenantId", tenantId);
#if DEBUG
var url = "http://localhost:5001/api/v1/RetrievePaymentDetails?orderpaymentid={orderPaymentId";
#else
//TODO: add URL once the application is in production!
var url = "intent2.api";
#endif
Policy
.Handle<HttpRequestException>()
.WaitAndRetry(new[]
{
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(15),
TimeSpan.FromSeconds(30)
});
using (HttpResponseMessage response = await client.GetAsync($"{url}"))
{
using (HttpContent content = response.Content)
{
HttpContentHeaders headers = content.Headers;
var result = JsonConvert.DeserializeObject<PaymentDetailsDto>(response.Content.ReadAsStringAsync().Result);
Currency currencyFromDb = (Currency)Enum.Parse(typeof(Currency), result.Currency);
var result2 = …Run Code Online (Sandbox Code Playgroud) 我有这样的工作流程:
两种 API 方法都具有相同类型的结果。我想通过 Polly 政策来实现这一点。
这是我的示例代码:
var retryPolicy = Policy
.Handle<HttpRequestException>(ex => ex.StatusCode == HttpStatusCode.RequestTimeout)
.RetryAsync(1, async (exception, retryCount) =>
await CallAnotherAPI());
var fallbackPolicy = Policy<HttpResponseMessage>
.Handle<Exception>()
.FallbackAsync((r, c, ct) => throw r.Exception,
async (r, c) =>
{
Log(r.Message);
});
var result = await fallbackPolicy
.WrapAsync(retryPolicy)
.ExecuteAsync(async () =>
{
await CallAPI();
});
Run Code Online (Sandbox Code Playgroud)
但它不起作用并且一直执行fallbackPolicy。如何编写如果retryPolicy为true,则不会执行fallbackPolicy的代码?
我在 Startup.ConfigureServices 方法中在 HttpClient 上创建了重试策略。另请注意,默认情况下,asp.net core 2.1 为 HttpClient 进行的每个调用记录 4 行 [信息] 行,这些行显示在我的问题末尾的日志中。
\nservices.AddHttpClient("ResilientClient")\n .AddPolicyHandler(\n Policy.WrapAsync(\n PollyRetryPolicies.TransientErrorRetryPolicy(),\n Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(60))));\nRun Code Online (Sandbox Code Playgroud)\n该策略定义如下。请注意,我将重试尝试写入日志,因此我会知道是否调用了重试策略。
\npublic static IAsyncPolicy < HttpResponseMessage > TransientErrorRetryPolicy() {\n return HttpPolicyExtensions\n .HandleTransientHttpError()\n .Or < TimeoutRejectedException > ()\n .WaitAndRetryAsync(sleepDurations: ExponentialBackoffPolicy.DecorrelatedJitter(3, SEED_DELAY, MAX_DELAY),\n onRetry: (message, timespan, attempt, context) => {\n context.GetLogger() ? .LogInformation($ "Retrying request to {message?.Result?.RequestMessage?.RequestUri} in {timespan.TotalSeconds} seconds. Retry attempt {attempt}.");\n });\n}\nRun Code Online (Sandbox Code Playgroud)\nHandleTransientHttpError() 是一个 Polly 扩展,它在注释中指出:
\n\n\n配置要处理的条件是:\n\xe2\x80\xa2 网络故障(如 System.Net.Http.HttpRequestException)
\n
我的httpclient用法是这样的:
\nusing (HttpResponseMessage …Run Code Online (Sandbox Code Playgroud) retry-logic ×10
c# ×5
polly ×5
android ×1
asp.net-core ×1
aws-sdk ×1
c++ ×1
fallback ×1
go ×1
http ×1
httpresponse ×1
interceptor ×1
java ×1
libcurl ×1
okhttp ×1
rest ×1
resttemplate ×1
retrofit2 ×1
spring ×1
timeout ×1