当前位置: 首页 > 知识库问答 >
问题:

Polly Retry-在重试成功之前,通过所有执行

翟修永
2023-03-14

目前,Polly Retry策略会独立退出所有失败的请求。因此,如果有10个请求失败,并且我已经设置了重试永远策略,那么每次重试发生时,它将发送10个以上的请求,服务器将永远不会愈合。

如何异步传递所有失败的请求,只重试一个请求,如果重试成功,恢复正常流程?

我不能(不想)使用断路器,因为我的服务是后台工作者服务,断路器破坏了整个后台服务逻辑。

// Current code with only retry policy
var retry = HttpPolicyExtensions.HandleTransientHttpError().WaitAndRetryForeverAsync(retryNo => new TimeSpan(0, retryNo > 3 ? 10 : (retryNo * 2), 0));
builder.Services.AddHttpClient<TestClient>().AddPolicyHandler(retry);

用例:我编写了一个后台服务,并不断地浏览一个包含30000页的网站。为了防止站点过载,我使用了信号量lim(或隔板)来限制在某个时间点发送到服务器的请求数量。

尽管如此,服务器还是有可能拒绝我的请求。此时,我只需要重试一个失败的请求单元,服务器就会再次开始接受我的请求。由于我同时发送多个请求,Polly正在重试所有失败的请求,这使服务器不满意。

期望:

10请求失败-

共有1个答案

杜楚
2023-03-14

据我所知,您有一个HttpClient,用于针对同一下游系统发出N个速率有限的并发请求。

您希望处理以下故障场景:

  • 如果存在瞬时网络问题,您希望重试单个请求
  • 如果下游系统过载(因此大多数并发请求失败),那么您希望后退并仅使用单个请求来探测其健康状况

断路器策略充当代理。它会跟踪传出的通信,如果连续出现太多故障,则会阻止进一步的请求。它通过抛出一个brokencircuiitexception来缩短请求。

在一段时间后,CB将允许单个请求针对下游系统发出,如果成功,则允许所有传出通信,但如果失败,则将缩短它们。这里我详细介绍了CB是如何工作的。

您可以调整重试策略以了解此异常。这意味着您的重试请求仍将发出,但不会离开您的应用程序域。幸运的是,在Polly中,您可以为策略定义多个触发器:

HttpPolicyExtensions
   .HandleTransientHttpError()
   .Or<BrokenCircuitException>()
   .WaitAndRetryForeverAsync(retryNo => new TimeSpan(0, retryNo > 3 ? 10 : (retryNo * 2), 0));

因此,它将触发一个HttpRequestExceptionbrokencircuiiteexception。如果HttpStatusCode为408或5xx,它也会触发。

现在剩下的就是将重试和断路策略组合成一个弹性策略。您可以使用以下方法之一来实现这一点:

.AddPolicyHandler(retryPolicy.Wrap(cbPolicy))
//OR
.AddPolicyHandler(Policy.Wrap(retryPolicy, cbPolicy))

请注意订购。重要的是将cb注册为内部策略,重试注册为外部策略,以便能够依赖升级。这里我已经详细描述了这个确切的场景。

注:如果你想,你可以在断路器断开时使用不同的延时。我在这里详细介绍了如何使用上下文对象来实现这一点。

如果应用程序没有崩溃,上述解决方案可以正常工作。如果是这样,那么你必须从头开始整个过程。

如果需要避免这种情况,那么需要将工作项(待处理的URL)存储在某个位置。

我建议采用以下架构:

  • 您的主要工作人员不会对下游系统发出http请求,而是创建作业/工作项
    • 它可以将工作项存储在数据库或持久队列中
    • 如果请求成功,则会从持久存储中删除工作项
    • 如果CB关闭,那么它将获得N个工作
    • 如果它是打开的,那么它只取一个

    使用这种体系结构,您不需要显式的重试策略,因为队列/数据库会保留那些未成功的项目。因此,获取逻辑将检索相同的作业,直到它最终完成。

    您可以通过创建死信队列来进一步扩展这个概念,您可以在其中存储失败N次的工作项。这样你的队列就不会被“永久”工作项污染。

 类似资料:
  • 问题内容: 我在代码中有很多地方可以处理Alamofire请求/响应。 由于某些间歇性问题(最常见的是不稳定的网络),每个请求都可能失败。 我希望能够在重试前重试请求3次。 直接的方法是拥有类似的东西 但是,出于多种原因,我不喜欢这种方法。最明显的是,我将需要为每种请求类型实现这样的代码(并且我有15种这样的代码)。 我很想知道是否有办法做类似的事情(变化很小且非侵入性) 问题答案: 通过Swif

  • 问题内容: 我的nodejs项目有以下文件 我使用提供环境变量的-e标志运行docker容器 但是我看不到替代品。当env变量可用时,会否执行Run ccommand? 问题答案: 图像是不可变的 Dockerfile定义了映像的构建过程。生成后,图像将是不可变的(无法更改)。运行时变量不会被添加到该不可变映像中。因此,Dockerfile是解决此问题的错误位置。 使用入口点脚本 您可能想做的是使

  • 问题内容: 我想为每个特定功能文件指定某些设置和拆卸步骤。我已经看到了允许在每个场景之前执行代码的钩子,并且允许在每个功能之前执行代码的钩子,但是我想指定代码在针对一个特定功能的所有场景下运行之前和之后运行一次。 这可能吗? 问题答案: 你用黄瓜jvm吗?我找到了适合您要求的文章。 http://zsoltfabok.com/blog/2012/09/cucumber-jvm- hooks/ 基本

  • 我想知道下面的问题是否有一个简单的解决方案。这里的问题是,我希望在初始条件为真后保留列表中出现的每个元素。这里的条件是,我想删除值大于18的条件之前的所有内容,但保留之后的所有内容。示例 输入: 预期产出: 我知道你可以通过 但是我想一旦找到18以上的第一个值就停止这个操作,然后包括其余的值,不管它们是否满足条件。这似乎是一个简单的问题,但我还没有找到解决办法。

  • 方法和测试位于一个类中,例如 下面是我的testng.xml的示例,其中包含了包含功能测试的包 UPD.post修改后的代码中包含AfterTest。我只使用before/aftermethod注释