当前位置: 首页 > 编程语言 > C#

如何改进这种异常重试方案?分享

时间:2023-04-10 21:40:37 C#

这个异常重试方案如何改进?我有一个我调用的Web服务方法,它是第三方并且在我的域之外。由于某种原因,Web服务有时会出现网关超时。它是间歇性的,在尝试失败后直接调用它可以成功。现在我遇到了编码难题,我有应该可以解决问题的代码,但代码看起来像是业余时间,您将在下面看到。这真的是糟糕的代码,还是可以接受的?如果不能接受,我该如何改进?看的时候尽量保持笔直。尝试{MDO=OperationsWebService.MessageDownload(MI);}catch{try{MDO=OperationsWebService.MessageDownload(MI);}catch{try{MDO=OperationsWebService.MessageDownload(MI);}catch{try{MDO=OperationsWebService.MessageDownload(MI);}catch{try{MDO=OperationsWebService.MessageDownload(MI);}catch(Exceptionex){//5次重试,现在可以记录并处理错误。}}}}}你可以循环执行。异常firstEx=null;for(inti=0;i<5;i++){try{MDO=OperationsWebService.MessageDownload(MI);firstEx=null;休息;}catch(Exceptionex){if(firstEx==null){firstEx=ex;}Thread.Sleep(100*(i+1));}}if(firstEx!=null){thrownewException("WebService调用在重试5次后失败。",firstEx);这是您尝试的另一种方法://如果您认为5次重试不适合您,则更容易更改ExceptionexceptionKeeper=null;for(inti=0;i我认为它更好地记录了意图。更少的代码也更容易维护。到目前为止,所有答案都假设对任何异常的反应应该是重试操作。这是一个很好的假设,直到它是错误的一。您可以通过重试轻松破坏系统,因为您没有检查异常类型。您几乎不应该使用简单的“catch”,也不应该使用“catch(Exceptionex)。”来捕获更具体的异常--一个你知道你可以安全恢复的人。尝试一个循环,有一些限制:intretryCount=5;变种完成=假;异常错误=空;while(!done&&retryCount>0){try{MDO=OperationsWebService.MessageDownload(MI);完成=真;}catch(Exceptionex){error=ex;}如果(完成)中断;重试次数--;您应该使用递归(或循环)并且只应在出现预期错误时重试。例如:staticvoidTryExecute(Actionmethod,FuncretryFilter,intmaxRetries)whereTException:Exception{try{method();}catch(TExceptionex){if(maxRetries>0&&retryFilter(ex))TryExecute(method,retryFilter,maxRetries-1);否则扔;}}编辑:循环:staticvoidTryExecute(Actionmethod,FuncretryFilter,intmaxRetries)whereTException:Exception{while(true){try{method();返回;}catch(TExceptionex){if(maxRetries>0&&retryFilter(ex))maxRetries--;否则扔;您可以尝试Thread.Sleep以防止retryFilter将来出现错误。如果最后一次重试失败,则抛出最终异常。这是我们正在使用的一些重试逻辑。我们不会做这么多,我会把它拉出来并将其记录为我们的重试模式/标准。我第一次写这篇文章时不得不放弃它,所以我来这里看看我是否做对了。看起来像我。以下版本已完全注释。请参阅下面的未注释版本。#regionSomeWebService.MyMethod的重试逻辑//以下代码将SomeWebService.MyMethod包装在重试逻辑中//以尝试解决网络故障、超时等问题。//在//之外声明SomeWebService.MyMethod的返回对象跟随for{}和try{}代码,以便我们之后拥有它。我的方法结果结果=空;//此逻辑将尝试重试对SomeWebService.MyMethod的调用for(intretryAttempt=1;retryAttempt我喜欢SamuelNeff使用异常变量来查看它是否完全失败。这将使我的逻辑中的一些评估更容易一些。我可以选择任何一个方向。不确定这两种方式是否有明显的优势。但是,在这个时候,我不会改变我们的做法。重要的是记录你在做什么,以及为什么一些白痴不会出现在你身后,把一切都搞砸了。但是,为了得到一个更好的主意,如果代码更短或更清晰,我会以某种方式放入所有注释。它们出现在完全相同的行数中。我继续编译这两个版本并通过ReflectorCodeMetrics运行它们并得到以下结果:Metric:Inside-Catch/Outside-ForCodeSize:197/185CyclomaticComplexity:3/3Instructions:79/80Locals:6/7Inthecatch最后的异常逻辑(第22行):MyMethodResultresult=null;for(intretryAttempt=1;thefinalexceptionlogicaftertheretryAttemptfor-loop(line22):MyMethodResultresult=null;ExceptionretryException=null;for(intretryAttempt=1;retryAttempt我正在使用以下通用方法重试场景。我特别想提请注意PreserveStackTrace方法,它有助于保留完整的调用堆栈跟踪,因为(正如我通过艰难的方式学到的),无论是throw还是throwex都不会产生完整的调用堆栈跟踪。publicstaticvoidRetryBeforeThrow(Actionaction,intretries,inttimeout)whereT:Exception{inttries=1;做{尝试{行动();返回;}catch(Tex){if(retries///在an上设置一个标志,以便在重新抛出异常时保留所有堆栈跟踪信息///。//////这很有用,因为“抛出"删除信息,例如原始堆栈帧。///publicstaticvoidPreserveStackTrace(Exceptionex){MethodInfopreserveStackTrace=typeof(Exception).GetMethod("InternalPreserveStackTrace",BindingFlags.Instance|BindingFlags.NonPublic);preserveStackTrace.Invoke(ex,null);}正如其他人指出的那样,正确的做法是用某种MAX_RETRY将try/catch包装在某个循环中。您还可以考虑在每个循环迭代之间添加一个超时。否则,您有风险在瞬态问题有机会自行解决之前通过重试燃烧计数器。看起来你有你需要的答案,但我想我会发布这个链接,什么是操作策略?,我发现它提供了一个更优雅的解决方案。Lokad有一些相当复杂的实现,但是这个的逻辑非常可靠,您最终编写的最终代码也非常简单。intcnt=0;布尔续=真;while(cont){try{MDO=OperationsWebService.MessageDownload(MI);续=假;}catch(Exceptionex){++cnt;if(cnt==5){//5次重试,ok现在记录并处理错误。续=假;}}}更新:基于评论的固定代码。以上就是C#学习教程:如何改进这种异常重试方案?如果分享的所有内容对您有用,需要了解更多C#学习教程,希望您多多关注---本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: