Polly同步超时策略问题:超时后重试实现及策略生效疑问
Polly超时与重试策略问题解答
一、乐观超时策略未生效的原因
Polly的Optimistic超时是协作式机制,它依赖执行逻辑主动响应CancellationToken来中断操作。你的代码中使用Thread.Sleep(5000),这个方法不支持取消——不管超时策略如何配置,它都会阻塞至5秒结束,超时策略根本无法触发,自然不会抛出TimeoutRejectedException。
要让乐观超时生效,必须将执行逻辑改为支持取消的形式,比如在同步代码中主动检查取消信号:
wrap.Execute((ct) => { "Enter executed logic".Dump(); for (int i = 0; i < 5; i++) { ct.ThrowIfCancellationRequested(); // 主动检测超时取消信号 Thread.Sleep(1000); } "Exit executed logic".Dump(); });
二、悲观策略下执行逻辑进入两次的原因
你当前的策略包裹顺序是Policy.Wrap(retry, timeout),即重试策略在外层,超时策略在内层。这个顺序的执行流程是:
- 第一次执行:内层超时策略触发,抛出
TimeoutRejectedException - 外层重试策略捕获异常,触发重试(你设置了
Retry(1),即最多重试1次) - 第二次执行:再次触发超时,重试次数耗尽,最终抛出异常
因此执行逻辑会被执行两次。
三、实现“超时后暂停并重试直至达到最大次数”的方案
要实现超时后暂停再重试,需做以下调整:
1. 保留合理的策略包裹顺序
保持重试策略在外,超时策略在内的顺序,确保每次执行逻辑都应用超时规则,超时后触发重试。
2. 用WaitAndRetry替代Retry
Retry是立即重试,WaitAndRetry可指定重试前的等待时间,比如每次超时后暂停2秒再重试:
var retry = Policy .Handle<TimeoutRejectedException>() // 仅捕获超时异常,避免无差别重试 .WaitAndRetry(2, retryAttempt => TimeSpan.FromSeconds(2), (ex, ts) => { $"超时,将在{ts.TotalSeconds}秒后重试".Dump(); });
3. 选择适配的超时策略
- 悲观超时(Pessimistic):无需修改执行逻辑,Polly会在独立线程执行逻辑,超时后强制终止并抛出
TimeoutRejectedException,重试策略捕获后触发等待重试。 - 乐观超时(Optimistic):必须修改执行逻辑,让它支持
CancellationToken,否则超时无法触发,重试也不会生效。
完整示例代码(悲观超时+等待重试)
var retry = Policy .Handle<TimeoutRejectedException>() .WaitAndRetry(2, retryAttempt => TimeSpan.FromSeconds(2), (ex, ts) => { $"超时,将在{ts.TotalSeconds}秒后重试".Dump(); }); var timeout = Policy .Timeout(1, Polly.Timeout.TimeoutStrategy.Pessimistic); var wrap = Policy.Wrap(retry, timeout); try { wrap.Execute(() => { "Enter executed logic".Dump(); Thread.Sleep(5000); "Exit executed logic".Dump(); }); } catch (TimeoutRejectedException ex) { $"最终超时:{ex.Message}".Dump(); }
是否必须让执行逻辑自身抛出超时?
- 悲观超时:不需要。Polly通过线程调度强制终止执行逻辑,直接抛出
TimeoutRejectedException。 - 乐观超时:必须。因为乐观超时是协作式的,需要执行逻辑主动检查
CancellationToken并抛出OperationCanceledException,Polly会将其包装为TimeoutRejectedException后抛出,才能被重试策略捕获。
内容的提问来源于stack exchange,提问作者iakob
相关产品推荐
相关产品推荐

